嘟嘟嘟

 

因为如果能跳x支舞曲,那么一定能跳y(y < x)支舞曲,满足单调性。因此可二分舞曲。

那么网络流建图就明白了:把每一个男生拆成3个点,分别是男生总,男生喜欢的,男生不喜欢的。然后从源点向男生总连一条容量为x的边,从男生总向男生喜欢的连一条INF的边,向男生不喜欢的连一条k的边。女生同理。

然后对于一对互相喜欢的男女生,就从男生喜欢的向女生喜欢的连一条1的边;对于不喜欢的男女生,就从男生不喜欢的向女生不喜欢的连一条1的边。跑一遍最大流,如果总流量等于x * n,就说明可以跳x支舞曲,向上二分。

[CQOI2009]跳舞_C  教程[CQOI2009]跳舞_编程开发_02
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("") 
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 50;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) {last = ch; ch = getchar();}
 26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) x = -x, putchar('-');
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36 
 37 int n, k, t;
 38 char a[maxn + 5][maxn + 5];
 39 
 40 struct Edge
 41 {
 42     int from, to, cap, flow;
 43 };
 44 vector<Edge> edges;
 45 vector<int> G[maxn * 6 + 5];
 46 void addEdge(int from, int to, int w)
 47 {
 48     edges.push_back((Edge){from, to, w, 0});
 49     edges.push_back((Edge){to, from, 0, 0});
 50     int sz = edges.size();
 51     G[from].push_back(sz - 2);
 52     G[to].push_back(sz - 1);
 53 }
 54 
 55 int dis[maxn * 6 + 5];
 56 bool bfs()
 57 {
 58     Mem(dis, 0); dis[0] = 1;
 59     queue<int> q; q.push(0);
 60     while(!q.empty())
 61     {
 62         int now = q.front(); q.pop();
 63         for(int i = 0; i < (int)G[now].size(); ++i)
 64         {
 65             Edge& e = edges[G[now][i]];
 66             if(!dis[e.to] && e.cap > e.flow)
 67             {
 68                 dis[e.to] = dis[now] + 1;
 69                 q.push(e.to);    
 70             }
 71         }
 72     }
 73     return dis[t];
 74 }
 75 int cur[maxn * 6 + 5];
 76 int dfs(int now, int res)
 77 {
 78     if(now == t || res == 0) return res;
 79     int flow = 0, f;
 80     for(int& i = cur[now]; i < (int)G[now].size(); ++i)
 81     {
 82         Edge& e = edges[G[now][i]];
 83         if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0)
 84         {
 85             e.flow += f;
 86             edges[G[now][i] ^ 1].flow -= f;
 87             flow += f; res -= f;
 88             if(res == 0) break;
 89         }
 90     }
 91     return flow;
 92 }
 93 
 94 int maxflow()
 95 {
 96     int flow = 0;
 97     while(bfs())
 98     {
 99         Mem(cur, 0);
100         flow += dfs(0, INF);
101     }
102     return flow;
103 }
104 
105 void build_Gra(int x)        //暴力重构 
106 {
107     edges.clear();            
108     for(int i = 0; i <= t; ++i) G[i].clear();
109     for(int i = 1; i <= n; ++i)
110     {
111         addEdge(0, i, x);
112         addEdge(i, n + i, INF); 
113         addEdge(i, (n << 1) + i, k);
114         addEdge(n * 5 + i, t, x); 
115         addEdge((n << 1) + n + i, n * 5 + i, INF);
116         addEdge((n << 2) + i, n * 5 + i, k);
117         for(int j = 1; j <= n; ++j) 
118         {
119             if(a[i][j] == 'Y') addEdge(n + i, (n << 1) + n + j, 1);
120             else addEdge((n << 1) + i, (n << 2) + j, 1); 
121         }
122     }
123 }
124 
125 int main()
126 {
127     n = read(); k = read();
128     t = (n << 2) + (n << 1) + 1;
129     for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1);
130     int L = 0, R = n;
131     while(L < R)
132     {
133         int mid = (L + R + 1) >> 1;
134         build_Gra(mid);
135         if(maxflow() == mid * n) L = mid;
136         else R = mid - 1;
137     }
138     write(L); enter;
139     return 0;
140 }
View Code