P6192-【模板】最小斯坦纳树

目录

P6192-【模板】最小斯坦纳树

给定一个包含 nn 个结点和 mm 条带权边的无向连通图 G=(V,E)G=(V, E)

再给定包含 kk 个结点的点集 SS,选出 GG 的子图 G=(V,E)G'=(V’, E’),使得:

  1. SVS\subseteq V'

  2. GG' 为连通图;

  3. EE' 中所有边的权值和最小。

你只需要求出 EE' 中所有边的权值和。

第一行:三个整数 n,m,kn, m, k,表示 GG 的结点数、边数和 SS 的大小。

接下来 mm 行:每行三个整数 u,v,wu, v, w,表示编号为 u,vu, v 的点之间有一条权值为 ww 的无向边。

接下来一行:kk 个互不相同的正整数,表示 SS 的元素。

第一行:一个整数,表示 EE' 中边权和的最小值。

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

1
2
11

fi,sf_{i, s}表示第 i 个点联通状态为 s 的最小代价 可以得到状态转移方程:

$$f_{i, s}=min\begin{cases}f_{i, ss}+f_{i, s\oplus ss}& & ss\in{s}\f_{j, s}+w_{i, j}& & 1\leq j\leq n\end{cases}$$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include "ybwhead/ios.h"
int n, m, k;
const int maxn = 1e3 + 10;
struct edge
{
    int v, w, nxt;
} e[maxn << 1];
int head[maxn], tot;
void __ADD(int u, int v, int w)
{
    e[++tot].v = v;
    e[tot].w = w;
    e[tot].nxt = head[u];
    head[u] = tot;
}
void add(int u, int v, int w)
{
    __ADD(u, v, w);
    __ADD(v, u, w);
}
priority_queue<pair<int, int>> q;
int f[maxn][maxn << 1];
void dij(int s)
{
    while (!q.empty())
    {
        int x = q.top().second;
        q.pop();
        for (int i = head[x]; i; i = e[i].nxt)
        {
            int v = e[i].v;
            if (f[v][s] > e[i].w + f[x][s])
            {
                f[v][s] = e[i].w + f[x][s];
                q.push(make_pair(-f[v][s], v));
            }
        }
    }
}
int ma;
int p[maxn];
int main()
{
    yin >> n >> m >> k;
    memset(f, 0x3f3f3f3f, sizeof(f));
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        yin >> u >> v >> w;
        add(u, v, w);
    }
    for (int i = 1; i <= k; i++)
    {
        yin >> p[i];
        f[p[i]][1 << (i - 1)] = 0;
    }
    ma = (1 << k) - 1;
    for (int s = 0; s <= ma; s++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int ss = (s - 1) & s; ss; ss = (ss - 1) & s)
            {
                f[i][s] = min(f[i][ss] + f[i][s ^ ss], f[i][s]);
            }
            if (f[i][s] != 0x3f3f3f3f)
                q.push(make_pair(-f[i][s], i));
        }
        dij(s);
    }
    yout << f[p[1]][ma] << endl;
    return 0;
}
来发评论吧~
Powered By Valine
v1.4.14