现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
思路:考虑最小生成树的性质:1)每种边权的边数相同(若不相同,答案就会改变);2)从小到大连晚某种边权后,点的连通状态相同(借助kruskal过程理解)。鉴于题目中相同边权的边不超过10条,我们可以对于每种边权的边dfs一下,判断可行的解,累乘起来就可以了。
#include<iostream> #include<cstdio> #include<algorithm> #define maxedge 1010 #define maxnode 110 #define P 31011 using namespace std; struct use{ int x1,x2,va,en; }edge[maxedge*2]={0}; int fa[maxnode]={0},nefa[maxnode]={0},lafa[maxnode]={0},cc,n; bool visit[maxedge*2]={false}; int my_comp(const use x,const use y) { if (x.va<y.va) return 1; else return 0; } int rool(int x) { if (fa[x]!=x) fa[x]=rool(fa[x]); return fa[x]; } int nerool(int x) { if (nefa[x]!=x) nefa[x]=nerool(nefa[x]); return nefa[x]; } bool judge(int fi,int up) { int i,j,r1,r2; for (i=1;i<=n;++i) nefa[i]=lafa[i]; for (i=fi;i<=up;++i) { if (visit[i]) { r1=nerool(edge[i].x1),r2=nerool(edge[i].x2); if (r1==r2) return false; if (r1<r2) nefa[r2]=r1; else nefa[r1]=r2; } } for (i=1;i<=n;++i) { nerool(i);rool(i); if (fa[i]!=nefa[i]) return false; } return true; } void dfs(int i,int tot,int la,int fi,int up) { int j; if (i>tot) { if (judge(fi,up)) { ++cc;if (cc>=P) cc-=P; } return; } for (j=la+1;j<=up;++j) { visit[j]=true; dfs(i+1,tot,j,fi,up); visit[j]=false; } } int main() { int m,i,j,tot,r1,r2,ans; scanf("%d%d",&n,&m); for (i=1;i<=m;++i) scanf("%d%d%d",&edge[i].x1,&edge[i].x2,&edge[i].va); sort(edge+1,edge+m+1,my_comp); for (i=1;i<=m;i=j+1) { j=i;edge[i].en=i; while(edge[j].va==edge[j+1].va) ++j; edge[i].en=j; } tot=0; for (i=1;i<=n;++i) fa[i]=i; for (i=1;i<=m;++i) { r1=rool(edge[i].x1);r2=rool(edge[i].x2); if (r1!=r2) { if (r1<r2) fa[r2]=r1; else fa[r1]=r2; ++tot; if (tot==n-1) break; } } if (tot<n-1) printf("0\n"); else { ans=1; for (i=1;i<=n;++i) fa[i]=i; for (i=1;i<=m;i=j) { tot=0; for (j=1;j<=n;++j) {rool(j);lafa[j]=fa[j];} for (j=i;j<=edge[i].en;++j) { r1=rool(edge[j].x1);r2=rool(edge[j].x2); if (r1!=r2) { if (r1<r2) fa[r2]=r1; else fa[r1]=r2; ++tot; } } cc=0; dfs(1,tot,i-1,i,edge[i].en); ans=(ans*cc)%P; } printf("%d\n",ans); } }
从这道题目中,对最小生成树有了新的认识。