Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P3264 [JLOI2015]管道连接

P3264 [JLOI2015]管道连接

和一般的斯坦纳树不同的是,不要求所有的特殊点连通,只要求每个颜色中的所有特殊点连通。考虑先求出一般的斯坦纳树,然后考虑子集合并。一种朴素的想法是对于每种颜色求出一个满足颜色中所有点连通的最小代价,但是发现合并两种颜色的时候如果边有交集会算重,可以注意到出现这种情况一定是满足两种颜色是连通的,可以直接从一般的斯坦纳树得到答案。预处理时,那么对于任意一种状态,求出其包含了哪些颜色,更新其答案。

查看代码
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <cstdio>
#include <queue>
#define mp make_pair
#define fi first
#define se second
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0';
flag && (x = ~x + 1);
}
template <class Type, class ...rest>
void read (Type &x, rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar('0' + x % 10);
}
typedef pair <int, int> PII;
const int N = 1e3 + 10, M = 6e3 + 10, K = 10, inf = 1e9;
bool vis[N];
int n, m, k, f[N][1 << K], h[K], g[1 << K];
int idx, hd[N], nxt[M], edg[M], wt[M];
void add (int a, int b, int c)
{
nxt[++idx] = hd[a];
hd[a] = idx;
edg[idx] = b;
wt[idx] = c;
}
int main ()
{
read(n, m, k);
for (int i = 1; i <= n; ++i) hd[i] = -1;
for (int a, b, c; m; --m)
{
read(a, b, c);
add(a, b, c), add(b, a, c);
}
for (int i = 1; i <= n; ++i)
for (int j = 0; j < 1 << k; ++j) f[i][j] = inf;
for (int i = 0, a, b; i < k; ++i)
{
read(a, b);
f[b][1 << i] = 0;
h[a - 1] |= 1 << i;
}
for (int s = 1; s < 1 << k; ++s)
{
priority_queue <PII, vector <PII> , greater <PII> > q;
for (int i = 1; i <= n; ++i) vis[i] = false;
for (int i = 1; i <= n; ++i)
{
for (int t = s; t; --t &= s)
f[i][s] = min(f[i][s], f[i][t] + f[i][s ^ t]);
if (f[i][s] ^ inf) q.push(mp(f[i][s], i));
}
while (!q.empty())
{
int t = q.top().se; q.pop();
if (vis[t]) continue;
vis[t] = true;
for (int i = hd[t]; ~i; i = nxt[i])
if (f[t][s] + wt[i] < f[edg[i]][s])
{
f[edg[i]][s] = f[t][s] + wt[i];
q.push(mp(f[edg[i]][s], edg[i]));
}
}
}
for (int i = 1; i < 1 << k; ++i) g[i] = inf;
for (int s = 1; s < 1 << k; ++s)
{
int t = 0, x = inf;
for (int i = 0; i < k; ++i)
if (s & h[i]) t |= h[i];
for (int i = 1; i <= n; ++i)
x = min(x, f[i][t]);
g[t] = min(g[t], x);
}
for (int s = 1; s < 1 << k; ++s)
for (int t = s; t; --t &= s)
g[s] = min(g[s], g[t] + g[s ^ t]);
write(g[(1 << k) - 1]);
return 0;
}