斯坦纳树DP。
首先记
f[i][sta]
表示经过节点
i
,节点状态为
再记
g[s]
表示颜色状态为
s
的最小花费,注意是颜色状态,每一位表示一个颜色集合,那么
显然直接用 g[2p−1] 数组作为答案是不对的,因为不同频道可以不连通。于是再DP一次,就能成功地把不连通的情况考虑进去啦,方程:
g[sta]=min(g[sta],g[s]+g[sta−s]),(s是sta的子状态)
为什么这个方程是正确的?因为他能够直接相加而不考虑交点呀。。。
代码又丑又慢,改了半天,跑了十多秒QAQ
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 20000005
#define N 1005
#define M 3005
#define P 11
using namespace std;
struct edge{int next,to,v;}e[M<<1];
struct color{int col,id;}c[P];
queue<int> q;
int cnt=1, n, m, p, last[N], col_sta[P], f[N][1<<P], g[1<<P], key_cnt=0, state=0;
bool inq[N];
void add(int a, int b, int c)
{
e[++cnt]=(edge){last[a],b,c};
last[a]=cnt;
}
void SPFA(int k)
{
while(!q.empty())
{
int x=q.front();
q.pop();
inq[x]=0;
for(int i = last[x]; i; i=e[i].next)
{
int y=e[i].to;
if(f[x][k]+e[i].v<f[y][k])
{
f[y][k]=f[x][k]+e[i].v;
if(!inq[y])
{
inq[y]=1;
q.push(y);
}
}
}
}
}
bool cmp(color a, color b){return a.col<b.col;}
int main()
{
memset(f,63,sizeof(f));
scanf("%d%d%d",&n,&m,&p);
for(int a, b, v, i = 0; i < m; i++)
{
scanf("%d%d%d",&a,&b,&v);
add(a,b,v);
add(b,a,v);
}
for(; key_cnt < p; key_cnt++)
scanf("%d%d",&c[key_cnt+1].col,&c[key_cnt+1].id);
sort(c+1,c+1+key_cnt,cmp);
int col_cnt=0;
for(int i = 1; i <= p; i++)
if(c[i].col!=c[i-1].col) col_cnt++;
c[0].col=c[1].col;
for(int i = 1, pos=1; i <= col_cnt; i++)
{
while(c[pos].col==c[pos-1].col)
c[pos-1].col=i,pos++;
c[pos-1].col=i;
pos++;
}
for(int i = 1; i <= p; i++)
{
col_sta[c[i].col]|=1<<(i-1);
f[c[i].id][1<<(i-1)]=0;
}
for(int sta=1; sta<(1<<key_cnt); sta++)
{
for(int j = 1; j <= n; j++)
{
for(int s=sta&(sta-1); s; s=(s-1)&sta)
f[j][sta]=min(f[j][sta],f[j][s]+f[j][sta-s]);
if(f[j][sta]<INF)
{
q.push(j);
inq[j]=1;
}
}
SPFA(sta);
for(int i = 1; i <= n; i++)
f[0][sta]=min(f[0][sta],f[i][sta]);
}
for(int i = 1; i < (1<<col_cnt); i++)
{
int j = i, t = 0;
for(int k = 1; j; j>>=1, k++)
{
if(j&1)
t|=col_sta[k];
}
g[i]=f[0][t];
}
for(int sta=1; sta<(1<<col_cnt); sta++)
for(int s=sta&(sta-1); s; s=(s-1)&sta)
g[sta]=min(g[sta],g[s]+g[sta-s]);
printf("%d\n",g[(1<<col_cnt)-1]);
}