【网络流24题 #04】魔术球问题
题目链接:魔术球问题
蒟蒻认为本题的关键还是在一个边与点的关系
本题一看就是图论…当然不少人(包括蒟蒻 是学习网络流来的…
显然我们要对球或杆进行操作
由于关系的建立条件是球的相邻放置条件
所以以球为元素建图 而一个杆子就是一条从起点到终点的路径
那么 最多能放的杆子数就是最小路径覆盖数
但是网络流维护的是边的关系
所以我们使用点拆边技能
把入度边和出度边分两个点存 然后在这两个点中间连一条路
注:公式:最小路径覆盖数=点数-最大匹配数
问题是题目给的是柱子数啊!
然鹅 对于能放的球数增加 柱子的数量单调增
因为球从下向上放 能放的球多了柱子数不可能减啊
debug中的错误:
1. S,T定太小 冲突 数组定太小
2. 反向边初始容量为0
3. 把next定成bool型。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main(){ 2 scanf("%d", &n); 3 int cnt = 0, now = 0; 4 memset(head, -1, sizeof(head)); 5 memset(next, -1, sizeof(next)); 6 S = N - 3, T = N - 2; 7 while(cnt <= n){ 8 now++; 9 addedge(S, now << 1, 1); addedge(now << 1 | 1, T, 1); 10 for(int i = sqrt(now) + 1; i * i < (now << 1); i++) 11 addedge((i * i - now) << 1, now << 1 | 1, 1); 12 if(!dinic()) ub[++cnt] = now; 13 } 14 printf("%d\n", --now); 15 for(int i = 1; i <= now; i++){ 16 if(!vis[i]){ 17 int k = i; 18 while(k < (S >> 1) && k != -1 && !vis[k]){ 19 printf("%d ", k); 20 vis[k] = 1; 21 k = next[k]; 22 } 23 printf("\n"); 24 } 25 } 26 return 0; 27 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <algorithm> 3 #include <queue> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 const int N = 1e6 + 5; 8 const int inf = 0x3f3f3f3f; 9 int n; 10 struct Edge{ 11 int u, v, w, next; 12 }edge[N << 1]; 13 int head[N], esize = -1; 14 bool vis[N]; 15 int next[N]; 16 int ub[N]; 17 inline void addedge(int x, int y, int z){ 18 edge[++esize] = (Edge){x, y, z, head[x]}; 19 head[x] = esize; 20 edge[++esize] = (Edge){y, x, 0, head[y]}; 21 head[y] = esize; 22 } 23 queue<int> q; 24 int dep[N]; 25 int S, T; 26 27 bool bfs(){ 28 int fro; 29 q.push(S); 30 memset(dep, 0, sizeof(dep)); 31 dep[S] = 1; 32 while(!q.empty()){ 33 fro = q.front(); q.pop(); 34 for(int i = head[fro]; i != -1; i = edge[i].next){ 35 int vv = edge[i].v; 36 if(!dep[vv] && edge[i].w > 0){ 37 dep[vv] = dep[fro] + 1; 38 q.push(vv); 39 } 40 } 41 } 42 return dep[T]; 43 } 44 45 int dfs(int x, int rest){ 46 if(x == T || !rest) return rest; 47 for(int i = head[x], vv, ww, d; i != -1; i = edge[i].next){ 48 vv = edge[i].v, ww = edge[i].w; 49 if(dep[vv] != dep[x] + 1) continue; 50 d = dfs(vv, min(rest, ww)); 51 if(d > 0){ 52 edge[i].w -= d; 53 edge[i ^ 1].w += d; 54 next[x >> 1] = (vv >> 1); 55 return d; 56 } 57 } 58 return 0; 59 } 60 61 bool dinic(){ 62 int ret = 0; 63 while(bfs()) 64 ret += dfs(S, inf); 65 return ret; 66 } 67 68 int main(){ 69 scanf("%d", &n); 70 int cnt = 0, now = 0; 71 memset(head, -1, sizeof(head)); 72 memset(next, -1, sizeof(next)); 73 S = N - 3, T = N - 2; 74 while(cnt <= n){ 75 now++; 76 addedge(S, now << 1, 1); addedge(now << 1 | 1, T, 1); 77 for(int i = sqrt(now) + 1; i * i < (now << 1); i++) 78 addedge((i * i - now) << 1, now << 1 | 1, 1); 79 if(!dinic()) ub[++cnt] = now; 80 } 81 printf("%d\n", --now); 82 for(int i = 1; i <= now; i++){ 83 if(!vis[i]){ 84 int k = i; 85 while(k < (S >> 1) && k != -1 && !vis[k]){ 86 printf("%d ", k); 87 vis[k] = 1; 88 k = next[k]; 89 } 90 printf("\n"); 91 } 92 } 93 return 0; 94 }