[CQOI2009]跳舞 网络流

题面:[CQOI2009]跳舞

题解:

  首先最大时间不好求,而且数据范围很小,所以我们可以先二分一个最大时间,然后就只需要判断是否可行即可。

  因此我们每二分一个mid,对于每个女生,连s ---> x : mid , x ---> x' : k.对于每个男生,连x ---> t : mid, x' ---> x : k.

  对于每条边,如果为Y,连x ---> y.否则连x' ---> y'.

  其中x和x'分别表示一个人和这个人拆分出来的点。

  为什么这么连?

  对于每个女生,连s ---> x : mid , x ---> x' : k。     其中s ---> x : mid 表示一共要进行mid次,x ---> x' : k表示这mid次中最多可以选k个和不喜欢的人相连。

  对于每个男生,连x ---> t : mid, x' ---> x : k.       同上。

  对于每条边,如果为Y,连x ---> y.否则连x' ---> y'.     如果是Y,说明互相喜欢,所以用原本的点相连,否则说明互相不喜欢,就用拆分出的点相连。因为拆分出的点最多只有k次机会,因此表示的是连向不喜欢的点。

  我一开始是这么想的,但是为了看上去简单一点,对于每个女生,我连了s --- > x : lim - k, s --- > x' : k.

  这样是不对的,因为这样就固定了喜欢的人也最多选lim - k个,而实际上是没有这个限制的。因此我们用x ---> x' : k的方法就可以去掉这个限制,并且可以让它相对动态的分配每次机会,而不是每次固定的只能选lim - k次喜欢的,和强制选k次不喜欢的。

  

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 400
  5 #define ac 40000
  6 #define inf 1000000000
  7 
  8 int n, m, ans, all, sum, s, t, head, tail, x, addflow, k;
  9 int Head[AC], Next[ac], date[ac], haveflow[ac], tot = 1;
 10 int have[AC], c[AC], good[AC], last[AC], q[ac];
 11 char f[AC][AC];
 12 
 13 inline int read()
 14 {
 15     int x = 0;char c = getchar();
 16     while(c > '9' || c < '0') c = getchar();
 17     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 18     return x;
 19 }
 20 
 21 void init()
 22 {
 23     memset(Head, 0, sizeof(Head));
 24     memset(have, 0, sizeof(have));
 25     memset(c, 0, sizeof(c));
 26     ans = 0, tot = 1;
 27 }
 28 
 29 inline void add(int f, int w, int S)
 30 {
 31     date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, haveflow[tot] = S;
 32     date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, haveflow[tot] = 0;
 33     //printf("%d %d : %d\n", f, w, S);
 34 }
 35 
 36 inline void upmin(int &a, int b){
 37     if(b < a) a = b;
 38 }
 39 
 40 void build(int lim)
 41 {
 42     sum = lim * m;
 43     for(R i = 1; i <= n; i ++) add(s, i, lim), add(i, n + i, k);
 44     for(R i = 1; i <= n; i ++)
 45         for(R j = 1; j <= m; j ++)
 46         {
 47             if(f[i][j] == 'Y') add(i, n + n + j, 1);
 48             else add(n + i, n + n + m + j, 1);
 49         }
 50     for(R i = 1; i <= m; i ++) add(n + n + i, t, lim), add(n + n + m + i, n + n + i, k);
 51 }
 52 
 53 void bfs()
 54 {
 55     head = tail = 0;
 56     q[++ tail] = t, c[t] = 1, have[1] = 1;
 57     while(head < tail)
 58     {
 59         int x = q[++ head];
 60         for(R i = Head[x]; i; i = Next[i])
 61         {
 62             int now = date[i];
 63             if(!c[now] && haveflow[i ^ 1])
 64                 ++ have[c[now] = c[x] + 1], q[++ tail] = now;
 65         }
 66     }
 67     memcpy(good, Head, sizeof(Head));
 68 }
 69 
 70 void aru()
 71 {
 72     while(x != s)
 73     {
 74         haveflow[last[x]] -= addflow;
 75         haveflow[last[x] ^ 1] += addflow;
 76         x = date[last[x] ^ 1];
 77     }
 78     ans += addflow;
 79 }
 80 
 81 void isap()
 82 {
 83     bool done = false;
 84     x = s, addflow = inf;
 85     while(c[s] != all)
 86     {
 87         if(x == t) aru(), addflow = inf;
 88         done = false;
 89         for(R i = good[x]; i; i = Next[i])
 90         {
 91             int now = date[i];
 92             good[x] = i;
 93             if(c[now] == c[x] - 1 && haveflow[i])
 94             {
 95                 done = true, x = now, last[now] = i;
 96                 upmin(addflow, haveflow[i]);
 97                 break;
 98             }
 99         }
100         if(!done)
101         {
102             int go = all - 1;
103             for(R i = Head[x]; i; i = Next[i])
104                 if(c[date[i]] && haveflow[i]) upmin(go, c[date[i]]);
105             if(!(-- have[c[x]])) break;
106             ++ have[c[x] = go + 1], good[x] = Head[x];
107             if(x != s) x = date[last[x] ^ 1];
108         }
109     }
110 }
111 
112 bool check(int lim)
113 {
114     init(), build(lim), bfs(), isap();
115     if(ans == sum) return true;
116     else return false;
117 }
118 
119 void half()
120 {
121     int l = 0, r = n, mid;
122     while(l < r)
123     {
124         mid = (l + r + 1) >> 1;
125         if(check(mid)) l = mid;
126         else r = mid - 1;
127     }
128     printf("%d\n", l);
129 }
130 
131 void pre()
132 {
133     n = read(), m = n, k = read();
134     s = n + n + m + m + 1, t = s + 1, all = t + 5;
135     for(R i = 1; i <= n; i ++) scanf("%s", f[i] + 1);
136 }
137 
138 int main()
139 {
140     freopen("in.in", "r", stdin);
141     pre();
142     half();
143     fclose(stdin);
144     return 0;
145 }
146  
View Code

猜你喜欢

转载自www.cnblogs.com/ww3113306/p/9960651.html