zoukankan      html  css  js  c++  java
  • BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索

    题目大意:给出一些边,求出一共能形成多少个最小生成树。


    思路:最小生成树有非常多定理啊,我也不是非常明确。这里仅仅简单讲讲做法。关于定各种定理请看这里:http://blog.csdn.net/wyfcyx_forever/article/details/40182739

    我们先做一次最小生成树。然后记录每一种长度的边有多少在最小生成树中,然后从小到大搜索,看每一种边权有多少种放法。然后全部的都算出来累乘就是终于的结果。


    CODE:

    #include <map>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define MAX 2010
    #define MO 31011
    using namespace std;
    
    map<int,int> G;
    
    struct Complex{
    	int x,y,len;
    
    	bool operator <(const Complex &a)const {
    		return len < a.len;
    	}
    	void Read() {
    		scanf("%d%d%d",&x,&y,&len);
    	}
    }edge[MAX];
    
    int points,edges;
    int ones[MAX];
    
    int father[MAX];
    int ans = 1;
    
    void Pretreatment()
    {
    	for(int i = 1;i <= 1025; ++i)
    		ones[i] = ones[i >> 1] + (i&1);
    }
    
    int Find(int x)
    {
    	if(!father[x] || father[x] == x)	return father[x] = x;
    	return father[x] = Find(father[x]);
    }
    
    bool Kruskal()
    {
    	int cnt = 0;
    	for(int i = 1;i <= edges; ++i) {
    		int fx = Find(edge[i].x);
    		int fy = Find(edge[i].y);
    		if(fx != fy) {
    			father[fy] = fx;
    			G[edge[i].len]++;
    			cnt++;
    		}
    	}
    	if(cnt < points - 1)	return false;
    	return true;
    }
    
    void DFS(int pos)
    {
    	if(pos > edges)	return ;
    	int st = pos,ed = pos,re = 0;
    	int cnt = G[edge[st].len];
    	if(!cnt) {
    		DFS(ed + 1);
    		return ;
    	}
    	while(edge[ed + 1].len == edge[st].len)	++ed;
    	for(int i = 0;i < (1 << (ed - st + 1)); ++i)
    		if(ones[i] == cnt) {
    			memset(father,0,sizeof(father));
    			int temp = i;
    			for(int j = st; temp; temp >>= 1,++j)
    				if(temp&1) {
    					int fx = Find(edge[j].x);
    					int fy = Find(edge[j].y);
    					if(fx == fy)	break;
    					father[fy] = fx;
    				}
    			if(!temp)	++re;
    		}
    	ans = (ans * re) % MO;
    	memset(father,0,sizeof(father));
    	for(int i = st; i <= ed; ++i) {
    		int fx = Find(edge[i].x);
    		int fy = Find(edge[i].y);
    		if(fx == fy)	continue;
    		father[fy] = fx;
    	}
    	for(int i = ed + 1;i <= edges; ++i)
    		edge[i].x = Find(edge[i].x),edge[i].y = Find(edge[i].y);
    	DFS(ed + 1);
    }
    
    int main()
    {
    	Pretreatment();
    	cin >> points >> edges;
    	for(int i = 1;i <= edges; ++i)
    		edge[i].Read();
    	sort(edge + 1,edge + edges + 1);
    	memset(father,0,sizeof(father));
    	if(!Kruskal()) {
    		cout << 0 << endl;
    		return 0;
    	}
    	DFS(1);
    	cout << ans << endl;
    	return 0;
    }


  • 相关阅读:
    迭代器简介
    关于判断对象是否相等的问题
    NIO
    BIO流分类介绍
    servlet简介
    http协议简介
    爬虫常用链接
    http和https协议
    爬虫的合法性研究
    爬虫介绍
  • 原文地址:https://www.cnblogs.com/yxysuanfa/p/6812458.html
Copyright © 2011-2022 走看看