直接求似乎不簡單,由於題目求”最大值最小問題”,可以轉化爲二分答案來驗證一個解是否成立.假設枚舉的答案是x,那麼所有人贏得的場次都<=x.而每場比賽最多隻有一個人獲勝,我們可以根據此信息,構圖:
設置源點與每個人建邊,每個人與它所參加的每場比賽建邊,每場比賽與超級匯點建邊並且流量設置爲1.根據此圖跑一遍最大流,判斷是否爲m即可.
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=10005;
const int oo=1e9+5;
int head[M<<1],n,m,u[M],v[M],ec=0,tot;
int dis[M<<1],flw[M<<1];// dis表示層數
struct node{
int to,cap,nex;
}e[M*8];//邊數 (n+3*m)*2
int Q[M<<2];
inline void rd(int &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<1)+(res<<3)+(c^48);
while(c=getchar(),c>=48);
}
void ins(int a,int b,int c){
e[ec]=(node){b,c,head[a]};
head[a]=ec++;
e[ec]=(node){a,0,head[b]};
head[b]=ec++;
}
bool BFS(){
memset(dis,-1,sizeof(dis));
int L=0,R=0,i,j,k;
dis[0]=0;
Q[R++]=0;
while(L<R){
int x=Q[L++];
if(x==tot)return true;
for(i=head[x];~i;i=e[i].nex){
int to=e[i].to,cap=e[i].cap;
if(dis[to]==-1&&cap){
dis[to]=dis[x]+1;
Q[R++]=to;
}
}
}
return false;
}
int dfs(int x,int flw){
if(x==tot)return flw;
int now=0;
for(int i=head[x];~i;i=e[i].nex){
int to=e[i].to,cap=e[i].cap;
if(dis[to]!=dis[x]+1||!cap)continue;
int f=dfs(to,min(flw,cap));
now+=f;
e[i].cap-=f;
e[i^1].cap+=f;
if(now==flw)break;
}
return now;
}
bool chk(int res){
memset(head,-1,sizeof(head));//初始化
ec=0;
int ans=0,i,j,k,a,b;
for(i=1;i<=n;i++)ins(0,i,res);
for(i=1;i<=m;i++){
ins(u[i],i+n,res);
ins(v[i],i+n,res);
ins(i+n,tot,1);
}//構圖
while(BFS()){
do a=dfs(0,oo),ans+=a;
while(a!=0);
}
if(ans==m)return true;
return false;
}
int main(){
int l,r,i,j,k,ans;
rd(n);rd(m);tot=n+m+1;
for(i=1;i<=m;i++){
rd(v[i]);rd(u[i]);
}
l=(m+n-1)/n;r=m;
while(l<=r){
int mid=l+r>>1;
if(chk(mid)){
ans=mid;r=mid-1;
}else l=mid+1;
}
printf("%d\n",ans);
return 0;
}