標籤:scan set pll http img inf font php 注意
http://www.lydsy.com/JudgeOnline/problem.php?id=1016
題意:
思路:
一個無向圖所有的最小產生樹中某種權值的邊的數目均相同。
引用一篇大牛的證明:
我們證明以下定理:一個無向圖所有的最小產生樹中某種權值的邊的數目均相同。
開始時,每個點單獨構成一個集合。
首先只考慮權值最小的邊,將它們全部添加進圖中,並去掉環,由於是全部嘗試添加,那麼只要是用這種權值的邊能夠連通的點,最終就一定能在一個集合中。
那麼不管添加的是哪些邊,最終形成的集合數都是一定的,且集合的劃分情況一定相同。那麼真正添加的邊數也是相同的。因為每添加一條邊集合的數目便減少1.
那麼權值第二小的邊呢?我們將之間得到的集合每個集合都縮為一個點,那麼權值第二小的邊就變成了當前權值最小的邊,也有上述的結論。
因此每個階段,添加的邊數都是相同的。我們以權值劃分階段,那麼也就意味著某種權值的邊的數目是完全相同的。
所以先用克魯斯卡爾演算法計算一遍最小產生樹,統計每一權值的邊組需要加幾條邊,最後暴搜,乘法原理相乘即可。注意,要判斷無法連通的情況。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,ll> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn=10000+5; 17 const int mod=31011; 18 19 struct node 20 { 21 int u,v,w; 22 }e[10*maxn]; 23 24 struct node2 25 { 26 int l,r; 27 int c; 28 }a[maxn]; 29 30 int n, m; 31 int sum; 32 int cnt,tot; 33 int p[maxn]; 34 35 bool cmp(node a, node b) 36 { 37 return a.w<b.w; 38 } 39 40 int find(int x) 41 { 42 return x==p[x]?x:find(p[x]); 43 } 44 45 void dfs(int cur, int num ,int pos) 46 { 47 if(pos>a[cur].r) 48 { 49 if(num==a[cur].c) sum++; 50 return; 51 } 52 int x=find(e[pos].u); 53 int y=find(e[pos].v); 54 if(x!=y) 55 { 56 p[x]=y; 57 dfs(cur,num+1,pos+1); 58 p[x]=x; 59 } 60 dfs(cur,num,pos+1); 61 } 62 63 int main() 64 { 65 //freopen("in.txt","r",stdin); 66 while(~scanf("%d%d",&n,&m)) 67 { 68 for(int i=1;i<=n;i++) p[i]=i; 69 for(int i=1;i<=m;i++) 70 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 71 72 sort(e+1,e+m+1,cmp); 73 cnt=0; tot=0; 74 for(int i=1;i<=m;i++) 75 { 76 if(e[i].w!=e[i-1].w) 77 { 78 a[++cnt].l=i; 79 a[cnt-1].r=i-1; 80 a[cnt].c=0; 81 } 82 int x=find(e[i].u); 83 int y=find(e[i].v); 84 if(x!=y) 85 { 86 p[x]=y; 87 a[cnt].c++; 88 tot++; 89 } 90 } 91 a[cnt].r=m; 92 93 if(tot!=n-1) //連不起來的情況 94 { 95 printf("0\n"); 96 continue; 97 } 98 99 100 for(int i=1;i<=n;i++) p[i]=i;101 int ans=1;102 for(int i=1;i<=cnt;i++)103 {104 sum=0;105 dfs(i,0,a[i].l);106 ans=(ans*sum)%mod;107 for(int j=a[i].l;j<=a[i].r;j++)108 {109 int x=find(e[j].u);110 int y=find(e[j].v);111 if(x!=y) p[x]=y;112 }113 }114 printf("%d\n",ans);115 }116 return 0;117 }
BZOJ 1016: [JSOI2008]最小產生樹計數