BZOJ 1305 dance跳舞 二分+最大流
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=1305
题目大意:
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
思路:
二分答案,判断是否可行,每次二分答案时,用以下方式建图即可,判断是否满流,满流的话就是可行解。
1 #include<bits/stdc++.h> 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时 4 #define Min(a, b) ((a) < (b) ? (a) : (b)) 5 #define Mem(a) memset(a, 0, sizeof(a)) 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1)) 7 #define MID(l, r) ((l) + ((r) - (l)) / 2) 8 #define lson ((o)<<1) 9 #define rson ((o)<<1|1) 10 #define Accepted 0 11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 17 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 21 typedef long long ll; 22 const int maxn = 1000 + 10; 23 const int MOD = 1000000007;//const引用更快,宏定义也更快 24 const int INF = 1e9 + 7; 25 const double eps = 1e-6; 26 struct edge 27 { 28 int u, v, c, f; 29 edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){} 30 }; 31 vector<edge>e; 32 vector<int>G[maxn]; 33 int level[maxn];//BFS分层,表示每个点的层数 34 int iter[maxn];//当前弧优化 35 36 void init(int n) 37 { 38 for(int i = 0; i <= n; i++)G[i].clear(); 39 e.clear(); 40 } 41 void addedge(int u, int v, int c) 42 { 43 e.push_back(edge(u, v, c, 0)); 44 e.push_back(edge(v, u, 0, 0)); 45 int m = e.size(); 46 G[u].push_back(m - 2); 47 G[v].push_back(m - 1); 48 } 49 void BFS(int s)//预处理出level数组 50 //直接BFS到每个点 51 { 52 memset(level, -1, sizeof(level)); 53 queue<int>q; 54 level[s] = 0; 55 q.push(s); 56 while(!q.empty()) 57 { 58 int u = q.front(); 59 q.pop(); 60 for(int v = 0; v < G[u].size(); v++) 61 { 62 edge& now = e[G[u][v]]; 63 if(now.c > now.f && level[now.v] < 0) 64 { 65 level[now.v] = level[u] + 1; 66 q.push(now.v); 67 } 68 } 69 } 70 } 71 int dfs(int u, int t, int f)//DFS寻找增广路 72 { 73 if(u == t)return f;//已经到达源点,返回流量f 74 for(int &v = iter[u]; v < G[u].size(); v++) 75 //这里用iter数组表示每个点目前的弧,这是为了防止在一次寻找增广路的时候,对一些边多次遍历 76 //在每次找增广路的时候,数组要清空 77 { 78 edge &now = e[G[u][v]]; 79 if(now.c - now.f > 0 && level[u] < level[now.v]) 80 //now.c - now.f > 0表示这条路还未满 81 //level[u] < level[now.v]表示这条路是最短路,一定到达下一层,这就是Dinic算法的思想 82 { 83 int d = dfs(now.v, t, min(f, now.c - now.f)); 84 if(d > 0) 85 { 86 now.f += d;//正向边流量加d 87 e[G[u][v] ^ 1].f -= d; 88 //反向边减d,此处在存储边的时候两条反向边可以通过^操作直接找到 89 return d; 90 } 91 } 92 } 93 return 0; 94 } 95 int Maxflow(int s, int t) 96 { 97 int flow = 0; 98 for(;;) 99 { 100 BFS(s); 101 if(level[t] < 0)return flow;//残余网络中到达不了t,增广路不存在 102 memset(iter, 0, sizeof(iter));//清空当前弧数组 103 int f;//记录增广路的可增加的流量 104 while((f = dfs(s, t, INF)) > 0) 105 { 106 flow += f; 107 } 108 } 109 return flow; 110 } 111 int n, k; 112 char Map[55][55]; 113 bool judge(int m) 114 { 115 int s = 0, t = 6 * n + 1; 116 init(t); 117 for(int i = 1; i <= n; i++) 118 { 119 addedge(s, i, m); 120 addedge(i, n + i, INF); 121 addedge(i, 2 * n + i, k); 122 addedge(3 * n + i, 5 * n + i, INF); 123 addedge(4 * n + i, 5 * n + i, k); 124 addedge(5 * n + i, t, m); 125 } 126 for(int i = 1; i <= n; i++) 127 { 128 for(int j = 1; j <= n; j++) 129 { 130 if(Map[i][j] == 'Y')//互相喜欢 131 addedge(n + i, 3 * n + j, 1); 132 else addedge(2 * n + i, 4 * n + j, 1); 133 } 134 } 135 return Maxflow(s, t) == n * m; 136 } 137 int main() 138 { 139 scanf("%d%d", &n, &k); 140 for(int i = 1; i <= n; i++)scanf("%s", Map[i] + 1); 141 int l = 0, r = n; 142 int ans = 0; 143 while(l <= r) 144 { 145 int m = (l + r) / 2; 146 if(judge(m))ans = m, l = m + 1; 147 else r = m - 1; 148 } 149 printf("%d\n", ans); 150 return Accepted; 151 }
越努力,越幸运