【BZOJ】【1532】【POI2005】Kos-Dicing
网络流/二分法
最大值最小……直接做不太好做的时候就可以用二分+判定来搞。
这题我们就也可以二分最大胜场v,那么怎么来判定呢?首先我们发现:每场比赛要么A赢,要么B赢,这一点跟二分图匹配非常类似,那么我们就可以建二分图:左部是参赛队伍,右边的结点表示每场比赛,对于第 i 场比赛:两支参赛队伍连x[i]->i+n和y[i]->i+n两条边,容量为1;连接i+n->T容量为1。对于第 j 支队伍,我们连S->j 容量为二分的最大胜场v。判定方法就是跑最大流,如果每场比赛都能分配出一个胜者(最大流=m)则当前v可行。
1 /************************************************************** 2 Problem: 1532 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:812 ms 7 Memory:2976 kb 8 ****************************************************************/ 9 10 //BZOJ 1532 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=20100,M=100010,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,m,tot,ans,x[N],y[N]; 32 struct edge{int to,v;}; 33 struct Net{ 34 edge E[M]; 35 int head[N],next[M],cnt; 36 void ins(int x,int y,int v){ 37 E[++cnt]=(edge){y,v}; 38 next[cnt]=head[x]; head[x]=cnt; 39 } 40 void add(int x,int y,int v){ 41 ins(x,y,v); ins(y,x,0); 42 } 43 int s,t,cur[N],d[N],Q[N]; 44 bool mklevel(){ 45 memset(d,-1,sizeof d); 46 d[s]=0; 47 int l=0,r=-1; 48 Q[++r]=s; 49 while(l<=r){ 50 int x=Q[l++]; 51 for(int i=head[x];i;i=next[i]) 52 if (d[E[i].to]==-1 && E[i].v){ 53 d[E[i].to]=d[x]+1; 54 Q[++r]=E[i].to; 55 } 56 } 57 return d[t]!=-1; 58 } 59 int dfs(int x,int a){ 60 if (x==t) return a; 61 int flow=0; 62 for(int &i=cur[x];i && flow<a;i=next[i]) 63 if (E[i].v && d[E[i].to]==d[x]+1){ 64 int f=dfs(E[i].to,min(a-flow,E[i].v)); 65 E[i].v-=f; 66 E[i^1].v+=f; 67 flow+=f; 68 } 69 if (!flow) d[x]=-1; 70 return flow; 71 } 72 void Dinic(){ 73 while(mklevel()){ 74 F(i,s,t) cur[i]=head[i]; 75 ans+=dfs(s,INF); 76 } 77 } 78 void build(int v){ 79 cnt=1;ans=0; 80 memset(head,0,sizeof head); 81 F(i,1,n) add(s,i,v); 82 F(i,1,m){ 83 add(i+n,t,1); 84 add(x[i],i+n,1); 85 add(y[i],i+n,1); 86 } 87 } 88 }G1; 89 int main(){ 90 #ifndef ONLINE_JUDGE 91 freopen("1532.in","r",stdin); 92 freopen("1532.out","w",stdout); 93 #endif 94 n=getint();m=getint(); 95 G1.s=0;G1.t=n+m+1; 96 F(i,1,m) x[i]=getint(),y[i]=getint(); 97 int l=1,r=m; 98 while(l<=r){ 99 int mid=l+r>>1; 100 G1.build(mid); 101 G1.Dinic(); 102 if (ans==m) r=mid-1; 103 else l=mid+1; 104 } 105 printf("%d\n",l); 106 return 0; 107 }
1532: [POI2005]Kos-Dicing
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1211 Solved: 382
[Submit][Status][Discuss]
Description
Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部.
俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的家伙,他想成为那个玩的最好的人,他现在知道了所有比赛的安排,他想知
道,在最好的情况下,他最少只需要赢几场就可以赢得冠军,即他想知道比赛以后赢的最多的那个家伙最少会赢多少场.
Input
第一行两个整数n 和 m, 1 <= n <=
10 000, 0 <= m <= 10 000; n 表示一共有多少个参赛者, m 表示有多少场比赛. 选手从1 到 n编号.
接下来m 行每行两个整数表示该场比赛的两个选手,两个选手可能比赛多场.
Output
第一行表示赢得最多的人最少会赢多少场
Sample Input
4 4
1 2
1 3
1 4
1 2
1 2
1 3
1 4
1 2
Sample Output
1