zoukankan      html  css  js  c++  java
  • [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
    ", 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("
    ");
    135             }
    136         }
    137     }
    138     return 0;
    139 }
  • 相关阅读:
    oracle 触发器的编写
    单例类与常见双下方法
    实现高效率的冒泡排序
    面向对象基础(五)
    面向对象基础(四)
    面向对象基础(三)
    面向对象基础(二)
    面向对象(基础)
    四指针法
    因数法
  • 原文地址:https://www.cnblogs.com/kirai/p/6793952.html
Copyright © 2011-2022 走看看