网络流 - 最大流构图入门 bzoj 1305
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。
Output
仅一个数,即舞曲数目的最大值。
Sample Input
3 0
YYY
YYY
YYY
Sample Output
3
Hint
N<=50 K<=30
题意 : 已知有 n 个男女,同时再给你一些男女之间的关系,告诉你每个男生喜欢哪几个女生,讨厌哪几个女生,并且只能和讨厌的女生最多跳 K 次舞蹈,问最终最多可以跳几次舞蹈
思路分析 :经典的最大流构图问题,考虑每个点都连出两个点,一个表示喜欢一个是不喜欢,建图后跑一次最大流即可。
代码示例 :
using namespace std; #define ll long long const int maxn = 300; const int mod = 1e9+7; const double eps = 1e-9; const double pi = acos(-1.0); const int inf = 0x3f3f3f3f; int n, k; char mp[55][55]; struct node{ int to, flow, next; }e[100000]; int head[maxn]; int cnt = 0, s, t; void addedge(int u, int v, int w){ e[cnt].to = v; e[cnt].flow = w; e[cnt].next = head[u]; head[u] = cnt++; e[cnt].to = u; e[cnt].flow = 0; e[cnt].next = head[v]; head[v] = cnt++; } int d[maxn], que[maxn]; bool bfs() { int head1 = 0, tail1 = 1; memset(d, 0, sizeof(d)); d[0] = 1, que[0] = s; while(head1 < tail1){ int u = que[head1++]; for(int i = head[u]; i != -1; i = e[i].next){ int to = e[i].to; if (e[i].flow && !d[to]){ d[to] = d[u]+1; que[tail1++] = to; } } } return d[t]; } int dfs(int u, int f1){ if (u == t) return f1; int f = 0; for(int i = head[u]; i != -1; i = e[i].next){ int to = e[i].to; if (e[i].flow && d[to] == d[u]+1){ int x = dfs(to, min(f1, e[i].flow)); e[i].flow -= x; e[i^1].flow += x; f1 -= x; f += x; } } if (!f) d[u] = -2; return f; } bool check(int x){ s = 0, t = 4*n+1; memset(head, -1, sizeof(head)); cnt = 0; for(int i = 1; i <= n; i++){ addedge(s, i, x); addedge(i, n+i, k); addedge(2*n+i, 3*n+i, k); addedge(3*n+i, t, x); } for(int i = 1; i <= n; i++){ for(int j = 1; j <= n; j++){ if (mp[i][j] == 'Y'){ addedge(i, 3*n+j, 1); } else addedge(n+i, 2*n+j, 1); } } int ret = 0; while(bfs()){ ret += dfs(s, inf); } if (ret == x*n) return true; return false; } int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); cin >> n >> k; for(int i = 1; i <= n; i++){ scanf("%s", mp[i]+1); } int l = 0, r = n; int ans; while(l <= r){ int mid = (l+r)>>1; if (check(mid)){ ans = mid; l = mid+1; } else r = mid-1; } printf("%d\n", ans); return 0; }
东北日出西边雨 道是无情却有情