Description
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的
最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生
成树可能很多,所以你只需要输出方案数对31011的模就可以了。
Input
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整
数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,0
00。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
Output
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
Sample Input
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8
这道题首先要用Kruskal求一次最小生成树,同时记录每种权值的边使用次数,由于对每棵最小生成树,其中每种权值的边的数量是相等的,所以再使用dfs+并查集计算每种边的使用方案,再用乘法原理即可,下面是程序:#include<stdio.h>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
const int mod=31011,N=105,M=1005;
struct edge{
int u,v,w;
bool operator <(const edge p)const{
return w<p.w;
}
}a[M];
vector<int>w[M];
int f[N],head[N],cnt[M];
void read(int &s){
s=0;
char c=getchar();
while(c<'0'||c>'9'){
c=getchar();
}
while(c>='0'&&c<='9'){
s*=10;
s+=c-'0';
c=getchar();
}
}
int findf1(int u){
return f[u]=u==f[u]?u:findf1(f[u]);
}
int findf2(int u){
while(u!=f[u]){
u=f[u];
}
return u;
}
int dfs(int i,int k,int s){
if(i==w[k].size()){
return s==cnt[k];
}
int tp=0;
if(s<cnt[k]){
int x=findf2(a[w[k][i]].u),y=findf2(a[w[k][i]].v);
if(x!=y){
f[x]=y;
tp+=dfs(i+1,k,s+1);
f[x]=x;
}
}
if(s+w[k].size()-i-1>=cnt[k]){
tp+=dfs(i+1,k,s);
}
return tp;
}
int main(){
int n,m,i,j,s=1,k=0,sum=0;
read(n);
read(m);
for(i=1;i<=m;i++){
read(a[i].u);
read(a[i].v);
read(a[i].w);
}
sort(a+1,a+m+1);
for(i=1;i<=n;i++){
f[i]=i;
}
for(i=1;i<=m;i++){
if(a[i].w!=a[i-1].w){
k++;
}
w[k].push_back(i);
int x=findf1(a[i].u),y=findf1(a[i].v);
if(x!=y){
f[x]=y;
cnt[k]++;
sum++;
}
}
if(sum<n-1){
printf("0\n");
return 0;
}
for(i=1;i<=n;i++){
f[i]=i;
}
for(i=1;i<=k;i++){
s*=dfs(0,i,0);
s%=mod;
for(j=0;j<w[i].size();j++){
int x=findf1(a[w[i][j]].u),y=findf1(a[w[i][j]].v);
if(x!=y){
f[x]=y;
}
}
}
printf("%d\n",s);
return 0;
}
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
const int mod=31011,N=105,M=1005;
struct edge{
int u,v,w;
bool operator <(const edge p)const{
return w<p.w;
}
}a[M];
vector<int>w[M];
int f[N],head[N],cnt[M];
void read(int &s){
s=0;
char c=getchar();
while(c<'0'||c>'9'){
c=getchar();
}
while(c>='0'&&c<='9'){
s*=10;
s+=c-'0';
c=getchar();
}
}
int findf1(int u){
return f[u]=u==f[u]?u:findf1(f[u]);
}
int findf2(int u){
while(u!=f[u]){
u=f[u];
}
return u;
}
int dfs(int i,int k,int s){
if(i==w[k].size()){
return s==cnt[k];
}
int tp=0;
if(s<cnt[k]){
int x=findf2(a[w[k][i]].u),y=findf2(a[w[k][i]].v);
if(x!=y){
f[x]=y;
tp+=dfs(i+1,k,s+1);
f[x]=x;
}
}
if(s+w[k].size()-i-1>=cnt[k]){
tp+=dfs(i+1,k,s);
}
return tp;
}
int main(){
int n,m,i,j,s=1,k=0,sum=0;
read(n);
read(m);
for(i=1;i<=m;i++){
read(a[i].u);
read(a[i].v);
read(a[i].w);
}
sort(a+1,a+m+1);
for(i=1;i<=n;i++){
f[i]=i;
}
for(i=1;i<=m;i++){
if(a[i].w!=a[i-1].w){
k++;
}
w[k].push_back(i);
int x=findf1(a[i].u),y=findf1(a[i].v);
if(x!=y){
f[x]=y;
cnt[k]++;
sum++;
}
}
if(sum<n-1){
printf("0\n");
return 0;
}
for(i=1;i<=n;i++){
f[i]=i;
}
for(i=1;i<=k;i++){
s*=dfs(0,i,0);
s%=mod;
for(j=0;j<w[i].size();j++){
int x=findf1(a[w[i][j]].u),y=findf1(a[w[i][j]].v);
if(x!=y){
f[x]=y;
}
}
}
printf("%d\n",s);
return 0;
}