这题又wa又T的,终于在y学长的帮助下A了,accept令人如此感动。。。。
不煽情了,开始题解
求瓶颈问题显然是二分的,那么我们可以二分最大值。
至于最大流建边,由超级源点向每场比赛建容量为1的边,由每场比赛向参赛者建容量为1的边,再由参赛者向汇点建容量为二分出的答案x的边,最大流与比赛场数相等时二分小答案
附代码(只写了三次最大流,代码略丑):
<strong>#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int n,m,nowp;
int head[20010];
int cur[20010];
int er[10001][2];
int pos=1;
struct edge
{int to,c,next;
}e[1000001];
void add(int a,int b,int c)
{pos++;e[pos].to=b,e[pos].c=c;e[pos].next=head[a];head[a]=pos;
}
int dis[100001];
queue<int>Q;
bool bfs()
{int i,j;for(int i=1;i<=n+m+2;i++)dis[i]=-1;dis[n+m+1]=0;while(!Q.empty()) Q.pop();Q.push(n+m+1);while(!Q.empty()){int u=Q.front();Q.pop();for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(e[i].c&&dis[v]<0){dis[v]=dis[u]+1;if(v==m+n+2)return 1;Q.push(v);}}}return 0;
}
int find(int x,int low)
{int a=0;int tmp=low;if(x==n+m+2)return low;for(int i=cur[x];i;i=e[i].next){int v=e[i].to;if(dis[v]==dis[x]+1&&e[i].c){a=find(v,min(tmp,e[i].c));e[i].c-=a;e[i^1].c+=a;tmp-=a;if(e[i].c)cur[x]=i;if(!tmp)return low;}}if(low==tmp)dis[x]=-1;return low-tmp;
}
bool check(int x)
{int ans=0;while(bfs()){for(int i=1;i<=n+m+2;i++)cur[i]=head[i];// printf("*\n");ans+=find(n+m+1,0x7fffffff);}return ans==m;
}
int ans;
void build(int mid)
{pos=1;memset(head,0,sizeof(head));int s=n+m+1,t=s+1;for(int i=1;i<=m;i++){add(s,n+i,1);add(n+i,s,0);}for(int i=1;i<=m;i++){add(n+i,er[i][0],1);add(er[i][0],n+i,0);add(n+i,er[i][1],1);add(er[i][1],n+i,0);}for(int i=1;i<=n;i++){add(i,t,mid);add(t,i,0);}
}
void solve()
{int l=1,r=m;while(l<=r){int mid=(l+r)>>1;build(mid);if(check(mid)){ans=mid;r=mid-1;}else l=mid+1;}
}
int a,b;
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);er[i][0]=a,er[i][1]=b;}solve();printf("%d\n",ans);
}
</strong>