【网络流24题 #04】魔术球问题

题目链接:魔术球问题

 

蒟蒻认为本题的关键还是在一个边与点的关系

本题一看就是图论…当然不少人(包括蒟蒻 是学习网络流来的…

 

显然我们要对球或杆进行操作

由于关系的建立条件是球的相邻放置条件

所以以球为元素建图 而一个杆子就是一条从起点到终点的路径

那么 最多能放的杆子数就是最小路径覆盖数

但是网络流维护的是边的关系

所以我们使用点拆边技能

把入度边和出度边分两个点存 然后在这两个点中间连一条路

 

注:公式:最小路径覆盖数=点数-最大匹配数

 

问题是题目给的是柱子数啊!

然鹅 对于能放的球数增加 柱子的数量单调增

因为球从下向上放 能放的球多了柱子数不可能减啊

 

debug中的错误:

1.    S,T定太小 冲突  数组定太小

2.    反向边初始容量为0

3.    把next定成bool型。。。

 

 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 }
关键部分
 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 }
Whole

 

posted @ 2018-07-07 15:50  hjmmm  阅读(223)  评论(0编辑  收藏  举报