我是靠谱客的博主 娇气外套,最近开发中收集的这篇文章主要介绍BZOJ5335:[TJOI2018]智力竞赛——题解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

https://www.lydsy.com/JudgeOnline/problem.php?id=5335

小豆报名参加智力竞赛,他带上了n个好朋友作为亲友团一块来参加比赛。
比赛规则如下:
一共有m道题目,每个入都有1次答题机会,每次答题为选择一道题目回答,在回答正确后,可以从这个题目的后续题目,直达题目答错题目或者没有后续题目。每个问题都会代表一个价值,比赛最后的参赛选手获得奖励价值等价于该选手和他的亲友团没有回答的问题中的最低价值。我们现在知道小豆和他的亲友团实力非常强,能够做出这次竞赛中的所有题目。
小豆想知道在知道题目和后续题目的条件下,他最大能获得价值是多少?

原来两点可达的floyd求法是传递闭包啊……

我们floyd求出每个点之间是否可达,然后根据这个建边,之后跑一遍最小路径覆盖即可,答案为节点数-最大匹配数。

那么对答案二分,则只有两点都小于答案的点才可以连边,跑一遍即可。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=550;
const int M=N*N;
inline int read(){
int X=0,w=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
struct node{
int to,nxt;
}e[M];
int vis[N],head[N],shu[N],cnt;
int w[N],mp[N][N],d[N][N],maxn,n,m;
inline void add(int u,int v){
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
bool dfs(int u,int id){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v]!=id){
vis[v]=id;
if(!shu[v]||dfs(shu[v],id)){
shu[v]=u;
return 1;
}
}
}
return 0;
}
inline void init(){
cnt=0;
memset(shu,0,sizeof(shu));
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
}
bool pan(int val){
init();
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]&&w[i]<val&&w[j]<val)d[i][j]=1;
}
}
for(int k=1;k<=m;k++){
for(int i=1;i<=m;i++){
if(!d[i][k])continue;
for(int j=1;j<=m;j++){
d[i][j]|=d[i][k]&d[k][j];
}
}
}
int ans=0;
for(int i=1;i<=m;i++){
if(w[i]<val)ans++;
else continue;
for(int j=1;j<=m;j++){
if(d[i][j])add(i,j);
}
}
for(int i=1;i<=m;i++){
if(w[i]>=val)continue;
if(dfs(i,i))ans--;
}
return ans<=n+1;
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
w[i]=read();int k=read();
maxn=max(maxn,w[i]);
for(int j=1;j<=k;j++){
int v=read();
mp[i][v]=1;
}
}
for(int k=1;k<=m;k++){
for(int i=1;i<=m;i++){
if(!mp[i][k])continue;
for(int j=1;j<=m;j++){
if(i==j)continue;
mp[i][j]|=mp[i][k]&mp[k][j];
}
}
}
int l=1,r=maxn+1;
while(l<r){
int mid=(l+r+1)>>1;
if(pan(mid))l=mid;
else r=mid-1;
}
if(l==maxn+1)puts("AK");
else printf("%dn",l);
return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

转载于:https://www.cnblogs.com/luyouqi233/p/9065606.html

最后

以上就是娇气外套为你收集整理的BZOJ5335:[TJOI2018]智力竞赛——题解的全部内容,希望文章能够帮你解决BZOJ5335:[TJOI2018]智力竞赛——题解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部