【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 }
View Code

 

1532: [POI2005]Kos-Dicing

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 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

Sample Output

1

HINT

Source

[Submit][Status][Discuss]
posted @ 2015-03-15 11:06  Tunix  阅读(205)  评论(0编辑  收藏  举报