bzoj 1016 最小生成树计数
首先能发现一个规律,就是重构最小生成树的时候,一定不可能用一条权值较大的边和一条权值较小的边去替换他们中间的两条边。简而言之,就是只能权值相同的边相互替换。再进一步说,就是每种权值的边的数目是一定的。 题目上说值相同的边最多10条,那么我们可以DFS选哪些,然后用并查集来判断是否成环。这里要注意,我们先kruskal把每种边选几条求出来,再按kruskal的顺序dfs每一种,每dfs一种,我们就要把这些边连起来(也就是边dfs边kruskal),这样可以确保求出每种边的组合是合法的。最后把它们乘起来就行了。
看一些题解上说如果相同的边多了要用矩阵,表示不太懂......
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define maxn 120 6 #define maxm 1200 7 #define ms 31011 8 using namespace std; 9 struct et 10 { 11 int s,t,val; 12 }e[maxm*2]; 13 int f[maxm],v[maxm],c[maxm],l[maxm],r[maxm],q[maxm]; 14 bool vis[maxm]; 15 int n,m,tot,num,now,cnt; 16 long long sum[maxm],ans; 17 18 int find(int i) 19 { 20 if (!f[i]) return i; 21 return find(f[i]); 22 } 23 24 void dfs(int col,int k,int ll) 25 { 26 if (k>v[col]) {sum[col]++;return;} 27 for (int i=ll+1;i<=r[col];i++) 28 { 29 int fx=find(e[i].s); 30 int fy=find(e[i].t); 31 if (fx!=fy) 32 { 33 int tmp=f[fx]; 34 f[fx]=e[i].t; 35 dfs(col,k+1,i); 36 f[fx]=tmp; 37 } 38 } 39 } 40 41 void add(int x,int y,int z) 42 { 43 e[++tot].s=x; e[tot].t=y; e[tot].val=z; 44 } 45 46 bool cmp(et a,et b) 47 { 48 return a.val<b.val; 49 } 50 51 int main() 52 { 53 int x,y,z; 54 scanf("%d %d",&n,&m); 55 for (int i=1;i<=m;i++) 56 { 57 scanf("%d %d %d",&x,&y,&z); 58 add(x,y,z); 59 } 60 sort(e+1,e+m+1,cmp); 61 int j=0; 62 for (int i=1;i<=m;i++) 63 { 64 if (e[i].val!=e[i-1].val) num++,l[num]=i; 65 r[num]=i,c[i]=num; 66 }//lisan 67 for (int i=1;i<=m;i++) 68 { 69 int fx=find(e[i].s),fy=find(e[i].t); 70 if (fx!=fy) 71 { 72 f[fx]=e[i].t; 73 v[c[i]]++; 74 } 75 }//kruskal 76 memset(f,0,sizeof(f)); 77 now=0; 78 for (int i=1;i<=m;i++) 79 { 80 if (now!=c[i]) now=c[i],dfs(now,1,l[now]-1); 81 int fx=find(e[i].s),fy=find(e[i].t); 82 if (fx!=fy) f[fx]=e[i].t,cnt++; 83 }//dfs 84 if (cnt<n-1) ans=0; else ans=1; 85 for (int i=1;i<=num;i++) if (sum[i]) ans*=sum[i],ans%=ms; 86 printf("%d\n",ans); 87 return 0; 88 }
AC without art, no better than WA !