2019.02.22【TJOI2018】【BZOJ5335】【洛谷P4589】智力竞赛(最小链覆盖)(二分答案)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/87877187

BZOJ传送门

洛谷传送门


解析:

显然你需要在自己脑子里补一个条件,不然就写一个tarjan求SCC。。。

这个图应该是DAG,如果不是,讨论会有点麻烦。

然后二分答案,看一下将答案以下的点全部覆盖至少需要多少条链就行了。

。。。

来吐槽几点。

首先,没有明说是DAG,其次没有明说一道题可以重复回答(这是最小链覆盖的基础要求,不然就是最小路径覆盖了)

难道TJOI没有验题人吗?


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

cs int N=505;
bool g[N][N];
int k,m,len;
int val[N];

inline void Floyd(){
	for(int re i=1;i<=m;++i){
		for(int re j=1;j<=m;++j){
			if(i^j)
			for(int re k=1;k<=m;++k){
				g[j][k]|=g[j][i]&&g[i][k];
			}
		}
	}
}

bool ban[N];
int match[N],vis[N];
int idx;
inline bool find(int u){
	if(ban[u])return false;
	for(int re v=1;v<=m;++v){
		if(!ban[v]&&g[u][v]&&(vis[v]^idx)){
			vis[v]=idx;
			if(!match[v]||find(match[v])){
				match[v]=u;
				return true;
			}
		}
	}
	return false;
}

inline bool check(int lim){
	for(int re i=1;i<=m;++i)ban[i]=val[i]>=lim;
	memset(match,0,sizeof match);
	++idx;
	for(int re i=1;i<=m;++i,++idx)find(i);
	int cnt=0;
	for(int re i=1;i<=m;++i)if(!ban[i]&&!match[i])++cnt;
	return cnt<=k+1;
}

int b[N];
signed main(){
	scanf("%d%d",&k,&m);
	for(int re i=1,tmp,x;i<=m;++i){
		scanf("%d%d",&val[i],&tmp);
		b[i]=val[i];
		while(tmp--){
			scanf("%d",&x);
			g[i][x]=true;
		}
	}
	Floyd();
	sort(b+1,b+m+1);
	len=unique(b+1,b+m+1)-b-1;
	if(check(b[len]+1))puts("AK"),exit(0);
	int l=1,r=len;
	while(l<r){
		int mid=(l+r+1)>>1;
		if(check(val[mid]))l=mid;
		else r=mid-1;
	}
	cout<<val[l]<<"\n";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/87877187
今日推荐