Description
给出一个nnn个点mmm条边的无向图,边有边权,对于这张图的任意一个有根生成树,定义其权值为
∑e∈{x,y}we⋅max(dx,dy)
\sum\limits_{e\in \{x,y\}}w_e\cdot max(d_x,d_y)
e∈{x,y}∑we⋅max(dx,dy)
其中dxd_xdx为xxx点在生成树中的深度,统计这张图所有有根生成树权值之和,结果模109+710^9+7109+7
Input
第一行输入两个整数n,mn,mn,m表示点数和边数,之后mmm行每行三个整数x,y,zx,y,zx,y,z表示x,yx,yx,y之间有一条权值为xxx的边
(1≤n≤12,1≤m≤1000,1≤x,y≤n,1≤z≤5000)(1\le n\le 12,1\le m\le 1000,1\le x,y\le n,1\le z\le 5000)(1≤n≤12,1≤m≤1000,1≤x,y≤n,1≤z≤5000)
Output
输出这张图所有有根生成树权值之和,结果模109+710^9+7109+7
Sample Input
4 5
1 2 1
1 3 3
1 4 1
2 3 4
3 4 1
Sample Output
303
Solution
考虑每条边e=(u,v,w)e=(u,v,w)e=(u,v,w)对答案的贡献,贡献分为两部分,uuu在生成树中是vvv的父亲节点以及vvv是uuu的父亲节点,以uuu是vvv的父亲节点为例,断掉这条边将树分成两个连通块,记vvv所在连通块为TTT,uuu所在连通块为SSS,此时需要求出以vvv为根的子树方案数g[T][v]g[T][v]g[T][v],而vvv节点的深度和实际上取决于uuu在SSS点集中的深度,以f[S][u]f[S][u]f[S][u]表示uuu在SSS状态的所有子树中的深度加一的和,那么我们只要求出f,gf,gf,g,即得答案为∑e∈E,S,Tw⋅(f[S][u]⋅g[T][v]+g[S][u]⋅f[T][v])\sum\limits_{e\in E,S,T}w\cdot (f[S][u]\cdot g[T][v]+g[S][u]\cdot f[T][v])e∈E,S,T∑w⋅(f[S][u]⋅g[T][v]+g[S][u]⋅f[T][v])
现在考虑状压求f,gf,gf,g,枚举点集SSS和SSS中一点uuu,下面要把SSS分解为两个不交的集合T,WT,WT,W,因为涉及到计数,故要有顺序,否则会记重,令TTT为包含S−{u}S-\{u\}S−{u}点集中最小编号的集合,WWW为TTT在SSS中的补,枚举TTT中一点vvv,考虑通过将T,WT,WT,W通过边u↔vu\leftrightarrow vu↔v合并进行对SSS状态的转移,首先有转移
g[S][u]+=g[W][u]⋅g[T][v]⋅num[u][v]
g[S][u]+=g[W][u]\cdot g[T][v]\cdot num[u][v]
g[S][u]+=g[W][u]⋅g[T][v]⋅num[u][v]
其中num[u][v]num[u][v]num[u][v]表示u↔vu\leftrightarrow vu↔v边的数量,主要考虑求f[S][u]f[S][u]f[S][u],u↔vu\leftrightarrow vu↔v边存在状态有两种:
1.uuu是vvv的父亲,那么此时uuu的深度不变,有转移
f[S][u]+=f[W][u]⋅g[T][v]⋅num[u][v]
f[S][u]+=f[W][u]\cdot g[T][v]\cdot num[u][v]
f[S][u]+=f[W][u]⋅g[T][v]⋅num[u][v]
2.vvv是uuu的父亲,此时uuu的深度为vvv的深度加一,vvv的深度加一之和为f[T][v]f[T][v]f[T][v],每种方案的深度要再加一才是uuu在这种方案下的深度,点集TTT构成一棵树的方案数为cnt[T]⋅g[T][v]cnt[T]\cdot g[T][v]cnt[T]⋅g[T][v],故有转移
f[S][u]+=(f[T][v]+cnt[T]⋅g[T][v])⋅g[W][u]⋅num[u][v]
f[S][u]+=(f[T][v]+cnt[T]\cdot g[T][v])\cdot g[W][u]\cdot num[u][v]
f[S][u]+=(f[T][v]+cnt[T]⋅g[T][v])⋅g[W][u]⋅num[u][v]
Code
#include<cstdio>
using namespace std;
typedef long long ll;
#define mod 1000000007
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
#define maxn (1<<12)
int n,m,e[5005][3],cnt[maxn],num[13][13],f[maxn][13],g[maxn][13];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
e[i][0]--,e[i][1]--;
num[e[i][0]][e[i][1]]++,num[e[i][1]][e[i][0]]++;
}
int N=(1<<n)-1;
for(int i=1;i<=N;i++)cnt[i]=cnt[i/2]+(i&1);
for(int S=1;S<=N;S++)
for(int u=0;u<n;u++)
if((S>>u)&1)
{
int SS=S^(1<<u);
int temp=SS&(-SS);
if(!SS)
{
f[S][u]=g[S][u]=1;
continue;
}
for(int T=SS;;T=(T-1)&SS)
{
if(T&temp)
for(int v=0;v<n;v++)
if((T>>v)&1)
{
int W=S^T;
int res=add(mul(f[W][u],g[T][v]),mul(add(f[T][v],mul(cnt[T],g[T][v])),g[W][u]));
f[S][u]=add(f[S][u],mul(res,num[u][v]));
g[S][u]=add(g[S][u],mul(mul(g[W][u],g[T][v]),num[u][v]));
}
if(!T)break;
}
}
int ans=0;
for(int i=0;i<m;i++)
{
int u=e[i][0],v=e[i][1],w=e[i][2];
for(int S=1<<u;S<=N;S=(S+1)|(1<<u))
ans=add(ans,mul(w,add(mul(f[S][u],g[N^S][v]),mul(g[S][u],f[N^S][v]))));
}
printf("%d\n",ans);
return 0;
}