P3425 [POI2005]KOS-Dicing
前置芝士:网络流
比较好的一道网络流题了,比较适合来练习思维和构图能力,还是老生常谈的一句话:图论的题就是构图
首先最难的一步,画出源点和汇点这里用 st 和 en 表示
好然后我们考虑将起点和每一场比赛连线,容量为 1,这个的意思就是每个比赛最多有一个人获胜,这里用粉色表示,因为粉色好康
然后将每一场比赛和相对应的两个人连线,容量为 1,代表这个人获胜或者是不获胜,这里用绿色表示
然后将所有人和终点连线
那么问题来了,容量为多少呢?
这个值我们不确定对吧,表示的是胜场的场数,所以我们要去枚举,怎么枚举呢
此题有可能还过不了,可能会 T 掉,所以简单的再观察亿下,可以发现,我们画的是二分图,所以曾广路会很短,所以我们可以缩小退出
然后就轻松的解决了这一题啦,代码也就很简单了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;
const int N=300010,M=80000010;
struct MS{
int from,to,next,z;
}e[M];
int elast[N],cur[N],k=1;
void print(int x,int y,int z){cout<<x<<"->"<<y<<"="<<z<<endl;}
void add(int x,int y,int z)
{
//print(x,y,z);
e[++k].to=y,e[k].from=x,e[k].z=z,e[k].next=elast[x],elast[x]=k;
e[++k].to=x,e[k].from=y,e[k].z=0,e[k].next=elast[y],elast[y]=k;
}
struct MSQWQ{
int x,y;
}a[N];
int n,m;
int ans;
int st,en;
int dis[N],cnt[N];
void bfs(int en)
{
queue<int>q;
q.push(en);
for(int i=0;i<=N-10;i++)cur[i]=elast[i],dis[i]=-1,cnt[i]=0;
dis[en]=0;
cnt[0]=1;
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=elast[now];i;i=e[i].next)
{
int to=e[i].to;
if(dis[to]==-1)
{
dis[to]=dis[now]+1;
cnt[dis[to]]++;
q.push(to);
}
}
}
}
int dfs(int x,int flow)
{
if(x==en)return flow;
int d=0;
for(int i=cur[x];i;i=e[i].next)
{
cur[x]=i;
int to=e[i].to;
if(e[i].z>0&&dis[x]==dis[to]+1)
{
int tmp=dfs(to,min(e[i].z,flow-d));
e[i].z-=tmp;
e[i^1].z+=tmp;
d+=tmp;
if(d==flow||dis[st]>=666)return d;
}
}
if(dis[st]>=666)return d;
cnt[dis[x]]--;
if(cnt[dis[x]]==0)dis[st]=666;
dis[x]++;
cur[x]=elast[x];
cnt[dis[x]]++;
return d;
}
int L,R,mid,qans;
int id[N];
bool check(int mid)
{
k=1;
memset(elast,0,sizeof(elast));
for(int i=1;i<=m;i++)add(st,i,1);
for(int i=1;i<=m;i++)
{
id[i]=k+1;
add(i,m+a[i].x,1);
add(i,m+a[i].y,1);
}
for(int i=1;i<=n;i++)add(m+i,en,mid);
ans=0;
bfs(en);
while(dis[st]<666)ans+=dfs(st,1e9);
if(ans>=m)return true;
return false;
}
int main()
{
scanf("%d%d",&n,&m);
st=0,en=n+m+1;
for(int i=1;i<=m;i++)scanf("%d%d",&a[i].x,&a[i].y);
L=m/n,R=m;
while(L<=R)
{
mid=(L+R)/2;
if(check(mid))qans=mid,R=mid-1;
else L=mid+1;
}
printf("%d\n",qans);
check(qans);
for(int i=1;i<=m;i++)
{
if(e[id[i]].z==0)printf("1\n");
else printf("0\n");
}
return 0;
}