zoukankan      html  css  js  c++  java
  • 斯坦纳树

    然而就是状压DP。

    具体来说,n个点中有k个关键点,选择一些边把它们连通。求最小边权和。

    f[i][s]表示点i与s关键点连通时的最小代价,注意i可以不是关键点。

    转移有两种,第一种是i不变,s变。枚举s的子集和补集即可。

    第二种是s不变,i变。把第一种转移中的所有非INF的i加入队列跑SPFA。每次从i转移到一个相邻点。

    例题:游览计划。这道题没有边权有点权,转移时的代价处理一下即可。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <queue> 
      4 
      5 const int N = 11, M = 101, INF = 0x3f3f3f3f;
      6 
      7 struct Edge {
      8     int nex, v;
      9 }edge[10010]; int tp;
     10 
     11 struct Pre {
     12     int f; // 0 merge 1 spfa
     13     int x, y;
     14     Pre(int F = -1) {
     15         f = F;
     16     }
     17 }pre[M][1 << 10];
     18 
     19 std::queue<int> Q;
     20 int G[N][N], f[M][1 << 10], n, m, cnt, /*imp[N], */e[M], vis[N];
     21 
     22 inline void add(int x, int y) {
     23     tp++;
     24     edge[tp].v = y;
     25     edge[tp].nex = e[x];
     26     e[x] = tp;
     27     return;
     28 }
     29 
     30 inline void exmin(int &a, int b) {
     31     a > b ? a = b : 0;
     32     return;
     33 }
     34 
     35 inline int val(int i) {
     36     return G[i / m][i % m];
     37 }
     38 
     39 inline int id(int x, int y) {
     40     return x * m + y;
     41 }
     42 
     43 inline void SPFA(int s) {
     44     while(!Q.empty()) {
     45         int x = Q.front();
     46         Q.pop(); // f[x][s]
     47         vis[x] = 0;
     48         for(int i = e[x]; i; i = edge[i].nex) {
     49             int y = edge[i].v;
     50             if(f[y][s] > f[x][s] + val(y)) {
     51                 f[y][s] = f[x][s] + val(y);
     52                 pre[y][s].f = 1;
     53                 pre[y][s].x = x;
     54                 if(!vis[y]) {
     55                     vis[y] = 1;
     56                     Q.push(y);
     57                 }
     58             }
     59         }
     60     }
     61     return;
     62 }
     63 
     64 void DFS(int i, int s) {
     65     if(val(i)) {
     66         G[i / m][i % m] = -1;
     67     }
     68     if(pre[i][s].f == -1) return;
     69     if(!pre[i][s].f) { // merge
     70         DFS(i, pre[i][s].x);
     71         DFS(i, pre[i][s].y);
     72     }
     73     else { // spfa
     74         DFS(pre[i][s].x, s);
     75     }
     76     return;
     77 }
     78 
     79 int main() {
     80     memset(f, 0x3f, sizeof(f));
     81     scanf("%d%d", &n, &m);
     82     for(int i = 0; i < n; i++) {
     83         for(int j = 0; j < m; j++) {
     84             scanf("%d", &G[i][j]);
     85             if(!G[i][j]) {
     86                 f[id(i, j)][1 << cnt] = 0;
     87 //                imp[cnt++] = id(i, j);
     88                 cnt++;
     89             }
     90             if(j < m - 1) add(id(i, j), id(i, j + 1));
     91             if(i < n - 1) add(id(i, j), id(i + 1, j));
     92             if(i) add(id(i, j), id(i - 1, j));
     93             if(j) add(id(i, j), id(i, j - 1));
     94         }
     95     }
     96     
     97     int lm = 1 << cnt;
     98     for(int s = 0; s < lm; s++) {
     99         for(int i = 0; i < n * m; i++) {
    100             // f[i][s]
    101             for(int j = (s - 1) & s; j; j = (j - 1) & s) {
    102                 int t = s ^ j;
    103 //                exmin(f[i][s], f[i][t] + f[i][j] - val(i));
    104                 if(f[i][s] > f[i][t] + f[i][j] - val(i)) {
    105                     f[i][s] = f[i][t] + f[i][j] - val(i);
    106                     pre[i][s].f = 0;
    107                     pre[i][s].x = t;
    108                     pre[i][s].y = j;
    109                 }
    110             }
    111             if(f[i][s] < INF) {
    112                 Q.push(i);
    113                 vis[i] = 1;
    114             }
    115         }
    116         SPFA(s);
    117     }
    118     
    119     int ans = INF, p;
    120     for(int i = 0; i < n * m; i++) {
    121         if(ans > f[i][lm - 1]) {
    122             ans = f[i][lm - 1];
    123             p = i;
    124         }
    125     } 
    126     
    127     DFS(p, lm - 1);
    128     
    129     printf("%d
    ", ans);
    130     for(int i = 0; i < n; i++) {
    131         for(int j = 0; j < m; j++) {
    132             if(G[i][j] == -1) putchar('o');
    133             else if(G[i][j] == 0) putchar('x');
    134             else putchar('_');
    135         }
    136         if(i < n - 1) puts("");
    137     }
    138     return 0;
    139 }
    AC代码

    例题:HDU4085 Peach Blossom Spring  斯坦纳森林(??这是什么词),先求出斯坦纳树然后再来一波DP。

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <queue>
      5 
      6 const int N = 51, M = 1010, INF = 0x3f3f3f3f;
      7 
      8 struct Edge {
      9     int nex, v, len;
     10 }edge[M << 1]; int tp;
     11 
     12 int f[N][1 << 10], g[1 << 10], valid[1 << 10], cnt[1 << 10];
     13 int e[N], n, m, k, lm;
     14 bool vis[N];
     15 std::queue<int> Q;
     16 
     17 inline void add(int x, int y, int z) {
     18     tp++;
     19     edge[tp].v = y;
     20     edge[tp].len = z;
     21     edge[tp].nex = e[x];
     22     e[x] = tp;
     23     return;
     24 }
     25 
     26 inline void exmin(int &a, int b) {
     27     a > b ? a = b : 0;
     28     return;
     29 }
     30 
     31 inline void out(int x) {
     32     for(int i = 0; i < k + k; i++) {
     33         printf("%d", (x >> i) & 1);
     34     }
     35     printf("
    ");
     36     return;
     37 }
     38 
     39 inline void clear() {
     40     memset(e, 0, sizeof(e));
     41     memset(valid, 0, sizeof(valid));
     42     tp = 0;
     43     return;
     44 }
     45 
     46 inline void SPFA(int s) {
     47 //    printf("SPFA : "); out(s);
     48     while(!Q.empty()) {
     49         int x = Q.front();
     50         Q.pop();
     51         vis[x] = 0;
     52         for(int i = e[x]; i; i = edge[i].nex) {
     53             int y = edge[i].v;
     54             if(f[y][s] > f[x][s] + edge[i].len) {
     55                 f[y][s] = f[x][s] + edge[i].len;
     56                 if(!vis[y]) {
     57                     vis[y] = 1;
     58                     Q.push(y);
     59                 }
     60             }
     61         }
     62     }
     63 //    printf("SPFA over 
    ");
     64     return;
     65 }
     66 
     67 inline void work() {
     68     memset(f, 0x3f, sizeof(f));
     69     memset(g, 0x3f, sizeof(g));
     70     scanf("%d%d%d", &n, &m, &k);
     71     lm = 1 << (k << 1);
     72     for(int i = 1, x, y, z; i <= m; i++) {
     73         scanf("%d%d%d", &x, &y, &z);
     74         add(x - 1, y - 1, z); add(y - 1, x - 1, z);
     75     }
     76     for(int i = 0; i < n; i++) f[i][0] = 0;
     77     for(int i = 0; i < k; i++) {
     78         f[i][1 << i] = 0;
     79         f[n - i - 1][1 << (i + k)] = 0;
     80     }
     81     for(int s = 0; s < lm; s++) {
     82         valid[s] = (cnt[s >> k] == cnt[s & ((1 << k) - 1)]);
     83 //        printf("s = ");    out(s);
     84         for(int i = 0; i < n; i++) {
     85             // f[i][s]
     86 //            printf("i = %d 
    ", i);
     87             for(int j = (s - 1) & s; j; j = (j - 1) & s) {
     88                 int t = s ^ j;
     89                 /*if(f[i][s] > f[i][t] + f[i][j]) {
     90                     printf("f = %d 
    ", f[i][t] + f[i][j]);
     91                 }*/
     92                 exmin(f[i][s], f[i][t] + f[i][j]);
     93             }
     94             if(f[i][s] < INF) {
     95                 vis[i] = 1;
     96                 Q.push(i);
     97             }
     98 //            printf("final f %d s = %d 
    ", i, f[i][s]);
     99         }
    100         SPFA(s);
    101         /*for(int i = 0; i < n; i++) {
    102             printf("final f %d s = %d 
    ", i, f[i][s]);
    103         }*/
    104         for(int i = 0; i < n; i++) {
    105             /*if(g[s] > f[i][s]) {
    106                 printf("i = %d g[s] = %d 
    ", i, f[i][s]);
    107             }*/
    108             exmin(g[s], f[i][s]);
    109         }
    110 //        printf("g = %d 
    ", g[s]);
    111     }
    112     // DP
    113     for(int s = 0; s < lm; s++) {
    114         for(int i = (s - 1) & s; i; i = (i - 1) & s) {
    115             if(!valid[i]) continue;
    116             exmin(g[s], g[i] + g[s ^ i]);
    117         }
    118     }
    119     if(g[lm - 1] == INF) {
    120         puts("No solution");
    121     }
    122     else {
    123         printf("%d
    ", g[lm - 1]);
    124     }
    125     return;
    126 }
    127 
    128 int main() {
    129 
    130     for(int i = 1; i < (1 << 10); i++) {
    131         cnt[i] = cnt[(i - (i & (-i))) >> 1] + 1;
    132     }
    133     int T;
    134     scanf("%d", &T);
    135     while(T--) {
    136 //        printf("T = %d 
    ", T);
    137         work();
    138         if(T) {
    139             clear();
    140         }
    141     }
    142     return 0;
    143 }
    AC代码

    亲测可以用dijkstra代替SPFA,条件是边权非负。本质上是多起点最短路。例题:BZOJ4774

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 10040, M = 265, INF = 0x3f3f3f3f;
      4 
      5 struct Edge {
      6     int nex, v, len;
      7 }edge[N << 1]; int tp;
      8 
      9 int n, e[N], f[N][M], g[M], ok[M];
     10 bool vis[N];
     11 
     12 inline void add(int x, int y, int z) {
     13     edge[++tp].v = y;
     14     edge[tp].len = z;
     15     edge[tp].nex = e[x];
     16     e[x] = tp;
     17     return;
     18 }
     19 
     20 struct Node {
     21     int x, d;
     22     Node(int X = 0, int D = 0) : x(X), d(D) {}
     23     inline bool operator < (const Node &w) const {
     24         return d > w.d;
     25     }
     26 };
     27 std::priority_queue<Node> Q;
     28 
     29 inline void dijkstra(int s) {
     30     while(Q.size()) {
     31         int x = Q.top().x;
     32         if(f[x][s] != Q.top().d) {
     33             Q.pop();
     34             continue;
     35         }
     36         Q.pop();
     37         for(int i = e[x]; i; i = edge[i].nex) {
     38             int y = edge[i].v;
     39             if(f[y][s] > f[x][s] + edge[i].len) {
     40                 f[y][s] = f[x][s] + edge[i].len;
     41                 Q.push(Node(y, f[y][s]));
     42             }
     43         }
     44     }
     45     return;
     46 }
     47 
     48 int main() {
     49     int m, d;
     50     scanf("%d%d%d", &n, &m, &d);
     51     for(int i = 1; i <= m; i++) {
     52         int x, y, z;
     53         scanf("%d%d%d", &x, &y, &z);
     54         if(x == y) continue;
     55         add(x, y, z);
     56         add(y, x, z);
     57     }
     58     memset(f, 0x3f, sizeof(f));
     59     for(int i = 1; i <= d; i++) {
     60         f[i][1 << (i - 1)] = 0;
     61         f[n - i + 1][1 << (i - 1 + d)] = 0;
     62     }
     63     int lm = (1 << (2 * d)) - 1;
     64     for(int s = 1; s <= lm; s++) {
     65         for(int i = 1; i <= n; i++) {
     66             for(int t = s & (s - 1); t; t = (t - 1) & s) {
     67                 f[i][s] = std::min(f[i][s], f[i][t] + f[i][s ^ t]);
     68             }
     69             if(f[i][s] != INF) {
     70                 Q.push(Node(i, f[i][s]));
     71             }
     72         }
     73         dijkstra(s);
     74     }
     75     int lm2 = (1 << d) - 1;
     76     for(int s = 1; s <= lm2; s++) {
     77         /// get sta
     78         int sta = 0;
     79         for(int i = 1; i <= d; i++) {
     80             if((s >> (i - 1)) & 1) {
     81                 sta |= (1 << (i - 1)) | (1 << (d + i - 1));
     82             }
     83         }
     84         sta ^= lm;
     85         g[s] = INF;
     86         for(int i = 1; i <= n; i++) {
     87             g[s] = std::min(g[s], f[i][lm]);
     88             for(int t = sta; t; t = (t - 1) & sta) {
     89                 g[s] = std::min(g[s], f[i][lm ^ t]);
     90             }
     91         }
     92     }
     93 
     94     for(int s = 1; s <= lm2; s++) {
     95         for(int t = (s - 1) & s; t; t = (t - 1) & s) {
     96             g[s] = std::min(g[s], g[t] + g[s ^ t]);
     97         }
     98     }
     99     if(g[lm2] == INF) g[lm2] = -1;
    100     printf("%d
    ", g[lm2]);
    101     return 0;
    102 }
    AC代码

    我有一个大胆的想法不知道当不当讲......SPFA,它死了。

  • 相关阅读:
    !!!C#——进制转换!
    冒泡排序后用二分查找法查找位置
    简陋的4位验证码程序(范围内取随机数)
    这个年龄计算程序相当不科学,体验还是差差哒
    8.7课堂随笔
    字符串中查询关键字
    !汉企的WiFi网速好快
    重度强迫症患者的九九乘法表
    自选数字和范围的整除算法
    day52
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10419743.html
Copyright © 2011-2022 走看看