[BZOJ5335][传递闭包][二分图匹配][二分]TJOI2018智力竞赛

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/87879125

BZOJ5335

一眼二分,然后把小于二分值的点的边连上
check就做最小链覆盖就行了

Code:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=550;
int tot=0,use[N],line[N];
int a[N][N],n,m,v[N];
inline void floyd(){
	for(int k=1;k<=m;k++)
		for(int i=1;i<=m;i++)
			for(int j=1;j<=m;j++)
				if(a[i][k] && a[k][j]) a[i][j]=1;
}
int pt[N];
int dfs(int v){
	for(int i=1;i<=tot;i++)
		if(!pt[i] && a[use[v]][use[i]]){
			pt[i]=1;
			if(!line[i] || dfs(line[i])){
				line[i]=v;
				return 1;
			}
		}
	return 0;
}
inline int check(int x){
	tot=0;
	for(int i=1;i<=m;i++) if(v[i]<x) use[++tot]=i;
	int ret=tot;
	for(int i=1;i<=tot;i++){
		memset(pt,0,sizeof(pt));
		ret-=dfs(i);
	}
	return ret;
}
int main(){
	int maxn=0;
	n=read()+1;m=read();
	for(int k,i=1;i<=m;i++){
		v[i]=read();k=read();maxn=max(maxn,v[i]);
		for(int y,j=1;j<=k;j++) y=read(),a[i][y]=1;
	}
	floyd();
	int l=1,r=maxn,mid;
	int ans=0;
	while(l<=r){
		int mid=(l+r)>>1;
		memset(line,0,sizeof(line));
		if(check(mid)<=n) ans=mid,l=mid+1;
		else r=mid-1;
	}
	if(ans>=maxn) cout<<"AK"<<endl;
	else cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/87879125
今日推荐