P3425 [POI2005]KOS-Dicing(最大流)

P3425 [POI2005]KOS-Dicing

开始一直想着把每个点拆分为输和赢两个状态

但还是不管用啊…

一场比赛只能有一个人赢…没必要储存输的情况啊!!

直接源点向比赛连边流量1

比赛向两个人连边流量分别是1,代表只能有一个人赢

然后二分一下就好了

我真是太菜了,哎

#include <bits/stdc++.h>
using namespace std;
#define id(x,y) (x-1)*m+y
const int maxn=2e5+10;
const int inf=1e9;
int n,m,s,t,sumn,dis[maxn],l[maxn],r[maxn];
struct edge{
	int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
	d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
	d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs()
{
	for(int i=0;i<=t;i++)	dis[i]=0;
	dis[s]=1;
	queue<int>q; q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		for(int i=head[u];i;i=d[i].nxt )
		{
			int v=d[i].to;
			if( d[i].flow&&dis[v]==0 )
			{
				dis[v]=dis[u]+1;
				if( v==t )	return true;
				q.push( v );
			}
		}
	}
	return false;
}
int dinic(int u,int flow)
{
	if( u==t )	return flow;
	int res=flow;
	for(int i=head[u];i&&res;i=d[i].nxt )
	{
		int v=d[i].to;
		if( dis[v]==dis[u]+1&&d[i].flow)
		{
			int temp=dinic(v,min(res,d[i].flow) );
			if( temp==0 )	dis[v]=0;
			res-=temp;
			d[i].flow-=temp;
			d[i^1].flow+=temp;
		}
	}
	return flow-res;
}
int ida[maxn],idb[maxn];
bool isok( int mid )
{
	cnt=1;
	memset(head,0,sizeof(head));
	s=0,t=n+m+1;
	int f=n;
	for(int i=1;i<=m;i++)
	{
		++f;
		add(s,f,1);
		add(f,l[i],1); ida[i]=cnt-1;
		add(f,r[i],1);	idb[i]=cnt-1;
	}
	for(int i=1;i<=n;i++)	add(i,t,mid);
	int ans=0;
	while( bfs() )	ans+=dinic(s,inf);
	return ans>=m;
}
int main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)	cin >> l[i] >> r[i];
	int L=1,R=m,mid,ans=0;
	while( R>=L )
	{
		mid = L+R>>1;
		if( isok(mid) )	R=mid-1,ans=mid;
		else	L=mid+1;
	}
	cout << ans << endl;
	isok( ans );
	for(int i=1;i<=m;i++)
	{
		int q=ida[i],w=idb[i];
		if( d[q].flow )	cout << 0 << '\n';
		else	cout << 1 << '\n';
	}
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108311686