当前位置: 首页 > 工具软件 > KOS > 使用案例 >

【POI 2005】KOS-Dicing

长孙鸿
2023-12-01

传送门


problem

n n n 个人,之间会有 m m m 场比赛。你可以设定所有比赛的结果。你希望获胜场次最多的人获胜的场次数尽量少,请求出这个最小值,并输出方案。

数据范围: 1 ≤ n , m ≤ 10000 1 \le n, m \le 10000 1n,m10000


solution

由于我们要最小化最大值,很明显的二分,假设现在二分到的值是 λ \lambda λ,考虑怎么 c h e c k check check

考虑网络流。从源点 S S S 向每个比赛连 1 1 1 的边,每个比赛向对应的两个人连 1 1 1 的边,然后每个人向汇点 T T T λ \lambda λ 的边(相当于限制了只能胜 λ \lambda λ 场)。

然后跑最大流,看最后的流量是否为 m m m(就是看 m m m 个比赛的胜负能否分配完),调整 λ \lambda λ 继续二分即可。

注意一下,最后还要 c h e c k check check 一遍 a n s ans ans,因为二分时最后 c h e c k check check 到的不一定是答案。


code

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,tot,S,T,now;
int first[N],v[N],w[N],nxt[N];
int U[N],V[N],d[N],f[N];
void add(int x,int y,int z){
	nxt[++tot]=first[x],first[x]=tot,v[tot]=y,w[tot]=z;
}
void build(int mid){
	tot=1,memset(first,0,sizeof(first));
	for(int i=1;i<=m;++i){
		add(S,i,1),add(i,S,0);
		add(i,m+U[i],1),add(m+U[i],i,0);
		add(i,m+V[i],1),add(m+V[i],i,0);
	}
	for(int i=m+1;i<=n+m;++i)  add(i,T,mid),add(T,i,0);
}
bool bfs(int S){
	memset(d,-1,sizeof(d));
	memcpy(f,first,sizeof(f));
	queue<int>Q;Q.push(S);d[S]=0;
	while(!Q.empty()){
		int x=Q.front();Q.pop();
		for(int i=f[x];i;i=nxt[i]){
			int to=v[i];
			if(w[i]&&d[to]==-1){
				d[to]=d[x]+1,Q.push(to);
			}
		}
	}
	return d[T]!=-1;
}
int dinic(int x,int flow){
	if(x==T)  return flow;
	int delta,ans=0;
	for(int &i=f[x];i;i=nxt[i]){
		int to=v[i];
		if(w[i]&&d[to]==d[x]+1){
			delta=dinic(to,min(flow,w[i]));
			w[i]-=delta,w[i^1]+=delta;
			flow-=delta,ans+=delta;
			if(!flow)  return ans;
		}
	}
	return ans;
}
bool check(int mid){
	build(mid),now=0;
	while(bfs(S))  now+=dinic(S,inf);
	return now==m;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)
		scanf("%d%d",&U[i],&V[i]);
	S=0,T=n+m+1;
	int l=1,r=m;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid))  r=mid;
		else  l=mid+1;
	}
	printf("%d\n",l),check(l);
	for(int i=1;i<=m;++i)
		for(int j=first[i];j;j=nxt[j])
			if(v[j]!=S&&(!w[j]))  puts(v[j]-m==U[i]?"1":"0");
	return 0;
}
 类似资料:

相关阅读

相关文章

相关问答