Description
小铭铭最近进入了某情报部门,该部门正在被如何创建安全的通道链接困扰。该部门有 n 个情报站,用 1 到 n 的整数编号。给出 m 对情报站 ui;vi 和费用 wi,表示情报站 ui 和 vi 之间能够花费 wi 单位资源创建通道。若是一个情报站通过若干个创建好的通道能够到达另一个情报站,那么这两个情报站就创建了通道链接。形式化地,若 ui 和 vi 创建了通道,那么它们创建了通道链接;若 ui 和 vi 均与 ti 创建了通道链接,那么 ui 和 vi 也创建了通道链接。如今在全部的情报站中,有 p 个重要情报站,其中每一个情报站有一个特定的频道。小铭铭面临的问题是,须要花费最少的资源,使得任意相同频道的情报站之间都创建通道链接。ios
Input
第一行包含三个整数 n;m;p,表示情报站的数量,能够创建的通道数量和重要情报站的数量。接下来 m 行,每行包含三个整数 ui;vi;wi,表示能够创建的通道。最后有 p 行,每行包含
两个整数 ci;di,表示重要情报站的频道和情报站的编号。安全
Output
输出一行一个整数,表示任意相同频道的情报站之间都创建通道链接所花费的最少资源总量。ui
Sample Input
5 8 4
1 2 3
1 3 2
1 5 1
2 4 2
2 5 1
3 4 3
3 5 1
4 5 1
1 1
1 2
2 3
2 4spa
Sample Output
4code
HINT
选择 (1; 5); (3; 5); (2; 5); (4; 5) 这 4 对情报站链接。
对于 100% 的数据,0 <ci <= p <= 10; 0 <ui;vi;di <= n <= 1000; 0 <= m <= 3000; 0 <= wi <=20000。ip
斯坦纳树+状压dpci
首先求出\(f_{sta}\)表示包含频率集合\(sta\)的最小斯坦纳生成森林的值,因而咱们有
\[f_{sta}=min\{f_s+f_{sta-s}|s\subset sta\}\]资源
而后,就瞎jb乱搞吧get
/*program from Wolfycz*/ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x7f7f7f7f using namespace std; typedef long long ll; typedef unsigned int ui; typedef unsigned long long ull; inline int read(){ int x=0,f=1;char ch=getchar(); for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1; for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; return x*f; } inline void print(int x){ if (x>=10) print(x/10); putchar(x%10+'0'); } const int N=1e3,M=3e3,K=10; int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10],tot; int f[N+10][(1<<K)+10],h[N+10],Ans[(1<<K)+10],sum[K+10],tmp[K+10]; bool vis[N+10]; struct S1{ int col,ID; void join(){col=read(),ID=read();} }imp[K+10];//important int n,m,k; void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;} bool check(int sta){ memset(tmp,0,sizeof(tmp)); for (int i=1;i<=k;i++) if ((1<<(i-1))&sta) tmp[imp[i].col]++; for (int i=1;i<=K;i++) if (tmp[i]&&tmp[i]!=sum[i]) return 0; return 1; } void spfa(int sta){ int head=0,tail=0; for (int i=1;i<=n;i++) h[++tail]=i,vis[i]=1; while (head!=tail){ if (++head>N) head=1; int Now=h[head]; for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){ if (f[son][sta]>f[Now][sta]+val[p]){ f[son][sta]=f[Now][sta]+val[p]; if (!vis[son]){ if (++tail>N) tail=1; vis[h[tail]=son]=1; } } } vis[Now]=0; } } int main(){ n=read(),m=read(),k=read(); for (int i=1;i<=m;i++){ int x=read(),y=read(),z=read(); join(x,y,z),join(y,x,z); } memset(f,63,sizeof(f)); memset(Ans,63,sizeof(Ans)); for (int i=1;i<=k;i++) imp[i].join(),sum[imp[i].col]++; for (int i=1;i<=k;i++) f[imp[i].ID][1<<(i-1)]=0; for (int sta=0;sta<1<<k;sta++){ for (int i=1;i<=n;i++) for (int s=(sta-1)&sta;s;s=(s-1)&sta) f[i][sta]=min(f[i][sta],f[i][s]+f[i][sta^s]); spfa(sta); } for (int sta=0;sta<1<<k;sta++) for (int i=1;i<=n;i++) Ans[sta]=min(Ans[sta],f[i][sta]); for (int sta=0;sta<1<<k;sta++){ if (!check(sta)) continue; for (int s=(sta-1)&sta;s;s=(s-1)&sta){ if (!check(s)) continue; Ans[sta]=min(Ans[sta],Ans[s]+Ans[sta^s]); } } printf("%d\n",Ans[(1<<k)-1]); return 0; }