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 }
  • 相关阅读:
    康复计划
    Leetcode 08.02 迷路的机器人 缓存加回溯
    Leetcode 38 外观数列
    Leetcode 801 使序列递增的最小交换次数
    Leetcode 1143 最长公共子序列
    Leetcode 11 盛水最多的容器 贪心算法
    Leetcode 1186 删除一次得到子数组最大和
    Leetcode 300 最长上升子序列
    Leetcode95 不同的二叉搜索树II 精致的分治
    Leetcode 1367 二叉树中的列表 DFS
  • 原文地址:https://www.cnblogs.com/kirai/p/6793952.html
Copyright © 2011-2022 走看看