题目描述
NiroBC 是猫咪学堂一年级的新生,开学第一天,学堂组织了一场迎新会,在
迎新会上,猫咪们会互相赠送礼物。
一年级的新生共有 N 只猫咪,编号为 1 . . . N(包括 NiroBC 自己),其中有
M 对猫咪是在开学前就互相认识的。学堂规定,对于任意一对已经互相认识的
猫咪 u, v,要么 u 送 v 一份礼物,要么 v 送 u 一份礼物。
学堂知道猫咪们都十分抠门,所以希望安排一种送礼物的方案,使得送出礼
物最多的猫咪送出的礼物最少。
输入格式
第一行两个正整数 N, M,表示猫咪的数量和已经互相认识的猫咪的对数。
接下来 M 行,每行两个整数 u, v,表示 u, v 已经互相认识。数据保证 u ̸= v,
且同一个数对最多出现一次((u, v) 和 (v, u) 算作同一数对)。
输出格式
一个整数,表示送出礼物最多的猫咪最少需要送出几份礼物。
分析:
由于决策单调性,所以可以二分答案,而判定mid的合法性可以跑最大流,将个关系
当作一个点,源点与这些点相连,容量为1,将这些关系的点与此关系的两个点连一条
容量为1的边,最后将这些人的点与汇点连接一条容量为mid的边,跑出最大流,若等
于关系数m,则合法,否则不合法。
代码:
#include<cstdio>
#include<cctype>
#define min(a,b) (a<b?a:b)
#define out(x) printf("%d",x)
#define inf 0x3f3f3f3f
#define maxn 1000007
#define maxm 1000007template <typename T> void in(T &x) {char ch=getchar();bool flag=0;while(ch>'9'||ch<'0') flag|=(ch=='-'),ch=getchar();x=ch-'0';ch=getchar();while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();if(flag) x=-x;return ;
}int n,m,s,t,cnt=1,cur[maxn],head[maxn],d[maxn],q[maxn];
struct edge{int to,cost,nxt;
}e[maxm];void link(int u,int v,int cost){e[++cnt].to=v;e[cnt].nxt=head[u];e[cnt].cost=cost;head[u]=cnt;e[++cnt].to=u;e[cnt].nxt=head[v];e[cnt].cost=0;head[v]=cnt;
}bool bfs(){for(int i=0;i<=t;i++)cur[i]=head[i],d[i]=0;int ha=1,ta=1,now;d[s]=1;q[1]=s;while(ha<=ta){now=q[ha++];for(int i=head[now];i;i=e[i].nxt)if(!d[e[i].to]&&e[i].cost){d[e[i].to]=d[now]+1;q[++ta]=e[i].to;if(e[i].to==t) return 1;}}return 0;
}int dfs(int u,int flow){if(u==t) return flow;int rest=flow;for(int w,i=cur[u];i;i=e[i].nxt){cur[u]=i;if(e[i].cost&&d[e[i].to]==d[u]+1){w=dfs(e[i].to,min(rest,e[i].cost));if(!w) { d[e[i].to]=0;continue;}e[i].cost-=w;e[i^1].cost+=w;rest-=w;if(rest==0) return flow;}}if(rest==flow)d[u]=0;return flow-rest;
}int maxflow=0;void dinic(){int w;maxflow=0;while(bfs())while(w=dfs(s,inf)) maxflow+=w;return ;
}void build(){in(n);in(m);s=0,t=n+m+5;for(int i=1,u,v;i<=m;i++){in(u);in(v);link(s,i,1);link(i,u+m,1);link(i,v+m,1);}for(int i=1;i<=n;i++)link(i+m,t,0);return ;
}bool work(int x){for(int i=head[s];i;i=e[i].nxt){e[i].cost=1;e[i^1].cost=0;}for(int i=1;i<=m;i++)for(int to,j=head[i];j;j=e[j].nxt){to=e[j].to;if(to!=s){e[j].cost=1;e[j^1].cost=0;}}for(int i=m+1;i<=n+m;i++)for(int to,j=head[i];j;j=e[j].nxt){to=e[j].to;if(to==t){e[j].cost=x;e[j^1].cost=0;}}dinic();if(maxflow==m) return 1;return 0;
}int main(){build();int l=1,ans=n,r=n,mid;while(l<=r){mid=(l+r)>>1;if(work(mid)) ans=mid,r=mid-1;else l=mid+1;}printf("%d",ans);return 0;
}