[swustoj1739] 魔术球问题 (最大流,最小路径覆盖)

题目链接:https://www.oj.swust.edu.cn/problem/show/1739

从1开始枚举球的个数,每次从残余网络更新总流量,最小路径覆盖刚好大于n时ret-1便是最多球。

之后根据容量为0的边找回匹配边即可。

用x << 1和x << 1 | 1拆点 比较方便。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 typedef struct Edge {
  5     int u, v, w, next;
  6 }Edge;
  7 
  8 const int inf = 0x7f7f7f7f;
  9 const int maxn = 100200;
 10 
 11 int cnt, dhead[maxn];
 12 int cur[maxn], dd[maxn];
 13 Edge dedge[maxn<<1];
 14 // bool vis[maxn]; // 记录经过的点
 15 int S, T, N;
 16 
 17 void init() {
 18     memset(dhead, -1, sizeof(dhead));
 19     for(int i = 0; i < maxn; i++) dedge[i].next = -1;
 20     S = 0; cnt = 0;
 21 }
 22 
 23 void adde(int u, int v, int w, int c1=0) {
 24     dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w; 
 25     dedge[cnt].next = dhead[u]; dhead[u] = cnt++;
 26     dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1; 
 27     dedge[cnt].next = dhead[v]; dhead[v] = cnt++;
 28 }
 29 
 30 bool bfs(int s, int t, int n) {
 31     // memset(vis, 0, sizeof(vis));
 32     queue<int> q;
 33     for(int i = 0; i < n; i++) dd[i] = inf;
 34     dd[s] = 0;
 35     q.push(s);
 36     while(!q.empty()) {
 37         int u = q.front(); q.pop();
 38         for(int i = dhead[u]; ~i; i = dedge[i].next) {
 39             if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) {
 40                 dd[dedge[i].v] = dd[u] + 1;
 41                 // vis[dedge[i].v] = 1;
 42                 if(dedge[i].v == t) return 1;
 43                 q.push(dedge[i].v);
 44             }
 45         }
 46     }
 47     return 0;
 48 }
 49 
 50 int dinic(int s, int t, int n) {
 51     int st[maxn], top;
 52     int u;
 53     int flow = 0;
 54     while(bfs(s, t, n)) {
 55         for(int i = 0; i < n; i++) cur[i] = dhead[i];
 56         u = s; top = 0;
 57         while(cur[s] != -1) {
 58             if(u == t) {
 59                 int tp = inf;
 60                 for(int i = top - 1; i >= 0; i--) {
 61                     tp = min(tp, dedge[st[i]].w);
 62                 }
 63                 flow += tp;
 64                 for(int i = top - 1; i >= 0; i--) {
 65                     dedge[st[i]].w -= tp;
 66                     dedge[st[i] ^ 1].w += tp;
 67                     if(dedge[st[i]].w == 0) top = i;
 68                 }
 69                 u = dedge[st[top]].u;
 70             }
 71             else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) {
 72                 st[top++] = cur[u];
 73                 u = dedge[cur[u]].v;
 74             }
 75             else {
 76                 while(u != s && cur[u] == -1) {
 77                     u = dedge[st[--top]].u;
 78                 }
 79                 cur[u] = dedge[cur[u]].next;
 80             }
 81         }
 82     }
 83     return flow;
 84 }
 85 
 86 int k, n;
 87 int path[maxn];
 88 bool vis[maxn];
 89 
 90 bool ok(int x) {
 91     int y = (int)sqrt(x);
 92     return x == y * y;
 93 }
 94 
 95 int main() {
 96     // freopen("in", "r", stdin);
 97     while(~scanf("%d", &n)) {
 98         init();
 99         S = 0, T = 10001, N = T + 1;
100         int ret = 0;
101         int flow = 0;
102         while(1) {
103             ret++;
104             for(int i = 1; i < ret; i++) {
105                 if(ok(i+ret)) adde(i<<1, (ret<<1)|1, 1);
106             }
107             adde(S, ret<<1, 1);
108             adde((ret<<1)|1, T, 1);
109             flow += dinic(S, T, N);
110             if(ret - flow > n) break;
111         }
112         memset(vis, 0, sizeof(vis));
113         memset(path, -1, sizeof(path));
114         printf("%d\n", ret-1);
115         int q = 0;
116         for(int i = 1; i < ret; i++) {
117             for(int j = dhead[i<<1]; ~j; j=dedge[j].next) {
118                 if(!dedge[j].w) {
119                     path[i] = dedge[j].v >> 1;
120                     break;
121                 }
122             }
123         }
124         for(int i = 1; i < ret; i++) {
125             if(!vis[i]) {
126                 vis[i] = 1;
127                 printf("%d", i);
128                 int j = path[i];
129                 while(j != 0 && j != T) {
130                     printf(" %d", j);
131                     vis[j] = 1;
132                     j = path[j];
133                 }
134                 printf("\n");
135             }
136         }
137     }
138     return 0;
139 }

 

posted @ 2017-05-02 00:04  Kirai  阅读(174)  评论(0编辑  收藏  举报