zoukankan      html  css  js  c++  java
  • 修路 BZOJ 4774

    修路

    【问题描述】

    村子间的小路年久失修,为了保障村子之间的往来,法珞决定带领大家修路。对于边带权的无向图 G = (V, E),请选择一些边,使得1 <= i <= d, i号节点和 n - i + 1 号节点可以通过选中的边连通,最小化选中的所有边的权值和。

    【输入格式】

    第一行两个整数 n, m,表示图的点数和边数。接下来的 m行,每行三个整数 ui, vi, wi,表示有一条 ui 与 vi 之间,权值为 wi 的无向边。

    【输出格式】

    一行一个整数,表示答案,如果无解输出-1

    【样例输入】

    10 20 1
    6 5 1
    6 9 4
    9 4 2
    9 4 10
    6 1 2
    2 3 6
    7 6 10
    5 7 1
    9 7 2
    5 9 10
    1 6 8
    4 7 4
    5 7 1
    2 6 9
    10 10 6
    8 7 2
    10 9 10
    1 2 4
    10 1 8
    9 9 7

    【样例输出】

    8

    【数据范围】

    1 <= d <= 4
    2d <= n <= 10^4
    0 <= m <= 10^4
    1 <= ui, vi <= n
    1 <= wi <= 1000

    题解:

    考虑到d灰常小,就是斯坦纳树啦

    用斯坦纳树求出以u为根,连通情况为opt的最小价值,记为f[u][opt]

    由于题目只要 i 与 n - i + 1 连通,那么取出所有对称的opt,取最小值,记为ans[opt]

    再暴力Dp合并

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cstdio>
      6 #include<cmath>
      7 using namespace std;
      8 inline void Scan(int &x)
      9 {
     10     char c;
     11     while((c = getchar()) < '0' || c > '9');
     12     x = c - '0';
     13     while((c = getchar()) >= '0' && c <= '9') x = x * 10 + c - '0';
     14 }
     15 const int maxn = 100233;
     16 const int inf = 707406378;
     17 int n, m, d, t, w;
     18 int num, all;
     19 bool vis[maxn];
     20 int ans[301], que[maxn];
     21 int f[maxn][301];
     22 int tot, nex[maxn], fir[maxn], ver[maxn], pri[maxn];
     23 inline void Ins(int x, int y, int z)
     24 {
     25     nex[++tot] = fir[x];
     26     fir[x] = tot;
     27     ver[tot] = y;
     28     pri[tot] = z;
     29 }
     30 inline void Reset()
     31 {
     32     memset(f, 127 / 3, sizeof(f));
     33     for(int i = 1; i <= d; ++i) f[i][1 << num++] = 0;
     34     for(int i = n - d + 1; i <= n; ++i) f[i][1 << num++] = 0;
     35     all = 1 << num;
     36 }
     37 inline void Spfa(int opt)
     38 {
     39     t = 0;
     40     while(t < w)
     41     {
     42         int u = que[++t];
     43         for(int i = fir[u]; i; i = nex[i])
     44         {
     45             int v = ver[i];
     46             if(f[u][opt] + pri[i] < f[v][opt])
     47             {
     48                 f[v][opt] = f[u][opt] + pri[i];
     49                 if(!vis[v])
     50                 {
     51                     vis[v] = true;
     52                     que[++w] = v;
     53                 }
     54             }
     55         }
     56         vis[u] = false;
     57     }
     58 }
     59 int main()
     60 {
     61     Scan(n), Scan(m), Scan(d);
     62     int x, y, z;
     63     for(int i = 1; i <= m; ++i)
     64     {
     65         Scan(x), Scan(y), Scan(z);
     66         Ins(x, y, z), Ins(y, x, z);
     67     }
     68     Reset();
     69     for(int opt = 0; opt < all; ++opt)
     70     {
     71         w = 0;
     72         for(int i = 1; i <= n; ++i)
     73         {
     74             for(int sub = opt; sub; sub = (sub - 1) & opt)
     75                 f[i][opt] = min(f[i][opt], f[i][sub] + f[i][opt ^ sub]);
     76             if(f[i][opt] != inf) que[++w] = i, vis[i] = true;
     77         }
     78         Spfa(opt);
     79         ans[opt] = inf;
     80     }
     81     bool flag;
     82     for(int opt = 0; opt < all; ++opt)
     83     {
     84         flag = false;
     85         for(int i = 0; i <= d; ++i)
     86         {
     87             bool a = (opt & (1 << i)) != 0;
     88             bool b = (opt & (1 << (d << 1) - i - 1)) != 0;
     89             if(a != b)
     90             {
     91                 flag = true;
     92                 break;
     93             }
     94         }
     95         if(flag) continue;
     96         for(int i = 1; i <= n; ++i) ans[opt] = min(ans[opt], f[i][opt]);
     97     }
     98     for(int opt = 0; opt < all; ++opt)
     99         for(int sub = opt; sub; sub = (sub - 1) & opt)
    100             ans[opt] = min(ans[opt], ans[sub] + ans[opt ^ sub]);
    101     if(ans[all - 1] != inf) printf("%d", ans[all - 1]);
    102     else printf("-1");
    103 }
  • 相关阅读:
    令Django 视图有默认 login_required
    sql语句 case
    java进制转换
    倒水问题
    全排列
    数据库范式
    操作系统——磁盘设备管理
    Windows系统安装MySQL
    Java题库——Chapter16 JavaFX UI组件和多媒体
    Java题库——Chapter15 事件驱动编程和动画
  • 原文地址:https://www.cnblogs.com/lytccc/p/6576039.html
Copyright © 2011-2022 走看看