【二分 最大流】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