【二分 最大流】bzoj1532: [POI2005]Kos-Dicing

晚上果然不适合调题目 

Description

Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部. 俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的家伙,他想成为那个玩的最好的人,他现在知道了所有比赛的安排,他想知道,在最好的情况下,他最少只需要赢几场就可以赢得冠军,即他想知道比赛以后赢的最多的那个家伙最少会赢多少场.

Input

第一行两个整数n 和 m, 1 <= n <= 10 000, 0 <= m <= 10 000; n 表示一共有多少个参赛者, m 表示有多少场比赛. 选手从1 到 n编号. 接下来m 行每行两个整数表示该场比赛的两个选手,两个选手可能比赛多场.

Output

第一行表示赢得最多的人最少会赢多少场

题目分析

因为一场比赛只有两个人,且必定会分出输赢,那么将人与比赛之间连一条容量为1的边;比赛与汇点之间连一条容量为1的边。再二分源点连向每一个人的容量mid,代表每一个人的最大获胜场数。每一次的check就是检查最大流是否达到m。

不知道为什么这题当前弧优化这么明显……以后写dinic还是三个优化都加好了。

  1 #include<queue>
  2 #include<cctype>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 const int maxn = 20035;
  7 const int maxm = 1000035;
  8 const int INF = 2e9;
  9 
 10 struct Edge
 11 {
 12     int u,v,f,c;
 13     Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {} 
 14 }edges[maxm];
 15 int n,m,S,T,L,R,ans;
 16 int edgeTot,head[maxn],cur[maxn],nxt[maxm],lv[maxn]; 
 17 
 18 int read()
 19 {
 20     char ch = getchar();
 21     int num = 0, fl = 1;
 22     for (; !isdigit(ch); ch=getchar())
 23         if (ch=='-') fl = -1;
 24     for (; isdigit(ch); ch=getchar())
 25         num = (num<<1)+(num<<3)+ch-48;
 26     return num*fl; 
 27 } 
 28 bool buildLevel()
 29 {
 30     memset(lv, 0, sizeof lv);
 31     std::queue<int> q;
 32     q.push(S), lv[S] = 1;
 33     for (int i=0; i<=n+m+2; i++) cur[i] = head[i];
 34     for (int tmp; q.size(); )
 35     {
 36         tmp = q.front(), q.pop();
 37         for (int i=head[tmp]; i!=-1; i=nxt[i])
 38         {
 39             int v = edges[i].v;
 40             if (!lv[v]&&edges[i].f < edges[i].c){
 41                 lv[v] = lv[tmp]+1, q.push(v);
 42                 if (v==T) return true;
 43             }
 44         }
 45     }
 46     return false;
 47 }
 48 int fndPath(int x, int lim)
 49 {
 50     if (x==T) return lim;
 51     for (int &i=cur[x]; i!=-1; i=nxt[i])
 52     {
 53         int v = edges[i].v, val;
 54         if (lv[x]+1==lv[v]&&edges[i].f < edges[i].c){
 55             if ((val = fndPath(v, std::min(lim, edges[i].c-edges[i].f)))){
 56                 edges[i].f += val, edges[i^1].f -= val;
 57                 return val;
 58             }else lv[v] = -1;
 59         }
 60     }
 61     cur[x] = head[x];
 62     return 0;
 63 }
 64 int dinic()
 65 {
 66     int ret = 0, val;
 67     while (buildLevel())
 68         while ((val = fndPath(S, INF))) ret += val;
 69     return ret;
 70 }
 71 void addedge(int u, int v, int c)
 72 {
 73     edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot++; 
 74     edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot++; 
 75 } 
 76 int main()
 77 {
 78     memset(head, -1, sizeof head); 
 79     n = read(), m = read();
 80     S = 0, T = n+m+1;
 81     for (int i=1; i<=n; i++) addedge(S, i, m);
 82     for (int i=1; i<=m; i++)
 83     {
 84         addedge(read(), n+i, 1); 
 85         addedge(read(), n+i, 1); 
 86         addedge(n+i, T, 1); 
 87     } 
 88     L = 0, R = m;
 89     for (int mid=(L+R)>>1; L<=R; mid=(L+R)>>1)
 90     {
 91         for (int i=0; i<n*2; i+=2)
 92             edges[i].c = mid, edges[i].f = 0, 
 93             edges[i^1].c = edges[i^1].f = 0;
 94         for (int i=n*2; i<edgeTot; i++)
 95             edges[i].f = 0;
 96         if (dinic() >= m) ans = mid, R = mid-1;
 97         else L = mid+1;
 98     } 
 99     printf("%d\n",ans);
100     return 0; 
101 } 

 

 

END

posted @ 2019-02-05 00:04  AntiQuality  阅读(134)  评论(0编辑  收藏  举报