斯坦纳树应用
点权关键联通
定义:\(f[i][bit]\)为联通快里包含\(i\)且关键点状态为\(bit\)的最小花费
初始化:\(~_{i=1}^k f[i][1<<i-1]=0;\)
实现:枚举\(bit\),枚举\(i\),枚举\(S\)
\(~~~~~~~~~~\)\(f[i][bit]=min_{S\in bit}\{f[i][S]+f[i][bit-S]-val[i]\}\)(容斥)
\(~~~~~~~~~~\)显然这样仅是合并(填表),还得有向外扩展的部分(刷表)
\(~~~~~~~~~~\)每次枚举\(bit\)最后遍历一遍图:\(f[j][bit]=f[i][bit]+val[j]\),\(e(i,j)\in \{E\}\)
\(~~~~~~~~~~\)注意此时即使\(j\)是关键点也不需要变化\(bit\)
边权有色关键联通
要求同色的关键点必须联通
对于颜色状压处理,状压处理的那些颜色单独作为关键点联通处理
对于之前的颜色状压做子集动规
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int Maxn = 0x3f3f3f3f;
const int N = 1005, M = 6005, L = 1 << 10;
int lst[N], f[N][L], nxt[M], to[M], cst[M], g[L], c[12];
int n, m, k, T, Cn; bool vis[N];
queue<int> Q;
template <class T> inline T Min(const T a, const T b) {return a < b? a : b;}
template <class T> inline void CkMin(T &a, const T b) {if (a > b) a = b;}
struct point
{
int col, id;
#define col(x) a[x].col
#define id(x) a[x].id
}a[12];
inline bool cmp(const point x, const point y) {return x.col < y.col;}
inline int get()
{
char ch; bool f = false; int res = 0;
while (((ch = getchar()) < '0' || ch > '9') && ch != '-');
if (ch == '-') f = true;
else res = ch - '0';
while ((ch = getchar()) >='0' && ch <= '9')
res = (res << 3) + (res << 1) + ch - '0';
return f? ~res + 1 : res;
}
inline void put(int x)
{
if (x < 0)
x = ~x + 1, putchar('-');
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}
inline void add(const int x, const int y, const int z)
{
nxt[++T] = lst[x]; lst[x] = T; to[T] = y; cst[T] = z;
nxt[++T] = lst[y]; lst[y] = T; to[T] = x; cst[T] = z;
}
inline void SPFA(const int I) {
int x, y;
while (!Q.empty()) {
x = Q.front();
vis[x] = false;
Q.pop();
for (int i = lst[x]; i; i = nxt[i])
if (f[y = to[i]][I] > f[x][I] + cst[i]) {
f[y][I] = f[x][I] + cst[i];
if (!vis[y])
vis[y] = true, Q.push(y);
}
}
}
inline int solve(const int cnt) {
int Cm = 1 << cnt;
for (int i = 1; i < Cm; ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = (i - 1) & i; k; k = (k - 1) & i)
CkMin(f[j][i], f[j][k] + f[j][i - k]); //边权不需要容斥
if (f[j][i] != Maxn)
vis[j] = true,
Q.push(j);
}
SPFA(i);
}
int res = Maxn;
for (int i = 1; i <= n; ++i) CkMin(res, f[i][Cm - 1]);
return res;
}
int main()
{
n = get(); m = get(); k = get(); int x, y;
for (int i = 1; i <= m; ++i)
{
x = get(); y = get();
add(x, y, get());
}
for (int i = 1; i <= k; ++i)
col(i) = get(),
id(i) = get(); //a
sort(a + 1, a + k + 1, cmp); //col
for (int i = 1; i <= k; ++i) {
if (col(i) != col(i - 1))
Cn++;
c[i] = Cn;
}
for (int i = 1; i <= k; ++i) col(i) = c[i]; //离散化
Cn = (1 << Cn);
memset(g, Maxn, sizeof(g));
for (int i = 1; i < Cn; ++i) {
memset(f, Maxn, sizeof(f));
int cnt = 0;
for (int j = 1; j <= k; ++j)
if ((1 << col(j) - 1) & i)
f[id(j)][1 << cnt++] = 0;
g[i] = solve(cnt);
}
for (int i = 1; i < Cn; ++i)
for (int j = (i - 1) & i; j; j = (j - 1) & i)
CkMin(g[i], g[j] + g[i - j]);
return put(g[Cn - 1]), 0;
}