继续畅通工程

Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

当N为0时输入结束。
 

Output
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
 

Sample Input
  
  
3 1 2 1 0 1 3 2 0 2 3 4 0 3 1 2 1 0 1 3 2 0 2 3 4 1 3 1 2 1 0 1 3 2 1 2 3 4 1 0
 

Sample Output
  
  
3 1 0
 
题解:最小生成树3种做法。把存在的费用设置为0就解决了存在的公路问题。因为如果存在的公路是最小生成树的边,那么我就+0,。

普里姆优化做法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>

using namespace std; //327ms ,vector耗时间 

const int INF = 105;

struct Node
{
	int to;
	int cost;
	Node(){}
	Node(int a,int b)
	{
		to = a;
		cost = b;
	}
	bool operator< (Node t) const
	{
		return cost > t.cost;
	}
};

priority_queue<Node> q;
vector<Node> vec[INF]; 
bool visited[INF];
int ans;

void prim(int n)
{
	memset(visited,false,sizeof(visited));
	ans = 0;
	for(int i = 0;i < vec[1].size();i++) //从1开始 
	{
		q.push(vec[1][i]);
	}
	visited[1] = true;
	
	int cnt = 0;
	while(!q.empty() && cnt < n -1)  //找到n-1条边 
	{
		Node t = q.top();
		q.pop();
		if(visited[t.to])       //访问过 
		{
			continue;
		}
		ans += t.cost;
		visited[t.to] = true;
		cnt++;
		for(int i = 0;i < vec[t.to].size();i++) //更新队列 
		{
			if(!visited[vec[t.to][i].to])
			{
				q.push(vec[t.to][i]);
			}
		}
	}
	
	printf("%d\n",ans);
	
	for(int i = 1;i <= n;i++)
	{
		vec[i].clear();
	}
	while(!q.empty())
	{
		q.pop();
	}
}

int main()
{
	int n;
	int u,v,c,s;
	while(scanf("%d",&n) && n != 0)
	{
		for(int i = 0;i < n * (n - 1) / 2;i++)
		{
			scanf("%d%d%d%d",&u,&v,&c,&s);
			if(0 == s)
			{
				vec[u].push_back(Node(v,c));
				vec[v].push_back(Node(u,c));
			}
			else
			{
			    vec[u].push_back(Node(v,0));
				vec[v].push_back(Node(u,0));
			}
		}
		
		prim(n);
	}
	
	return 0;
 } 

普里姆:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;    //运行时间327ms 

const int INF = 0x3fffffff;

int map[101][105];
bool visited[105];
int e[105];
int ans;

void prim(int n)
{
	memset(visited,false,sizeof(visited));
	ans = 0;
	for(int i = 1;i <= n;i++)
	{
		e[i] = map[1][i];      //从1开始找 
	}
	e[1] = 0;
	visited[1] = true;
	
	for(int i = 1;i < n;i++) //找n-1条边 
	{
		int min = INF;       
		int k;
		for(int j = 1;j <= n;j++)
		{
			if(!visited[j] && min > e[j])  //找到最小边 
			{
				min = e[j];
				k = j;
			}
		}
		
		ans += min;       //找到了一条 
		visited[k] = true; 
		
		for(int j = 1;j <= n;j++)     //更新数组最小值 
		{
			if(!visited[j] && e[j] > map[k][j])
			{
				e[j] = map[k][j];
			}
		}
	}
	
	printf("%d\n",ans);
}

int main()
{
	int n;
	int u,v,c,s;
	while(scanf("%d",&n) && n != 0)
	{
		for(int i = 0;i < n * (n - 1) / 2;i++)
		{
			scanf("%d%d%d%d",&u,&v,&c,&s);
			if(0 == s)
			{
				map[u][v] = c;
				map[v][u] = c;
			}
			else
			{
				map[u][v] = 0;      //表示不需要花费钱了 
				map[v][u] = 0;
			}
		}
		
		prim(n);
	}
	

	return 0;
}

克鲁斯卡尔:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;     //运行时间493ms

struct Node
{
	int u;
	int v;
	int cost;
	Node(){}
	Node(int a,int b,int c)
	{
		u = a;
		v = b;
		cost = c;
	}
	bool operator< (Node t) const
	{
		return cost < t.cost;
	}
};

Node e[10005];
bool visited[105];
int fa[105];
int ans;

int find(int x)  //并查集 
{
	if(x == fa[x])
	{
		return x;
	}
	
	return fa[x] = find(fa[x]);
}

void kruskal(int n)
{
    sort(e,e + n * (n - 1) / 2); //排序后找最小边 
	
	int k = 0;
	for(int i = 1;i < n;i++)      //n-1条边 
	{ 
	    for(int j = k;j < n * (n - 1) / 2;j++)
		{
			int x = find(e[j].u);
			int y = find(e[j].v);
			if(x == y)              //判断是不是同一个集合 
			{ 
				continue;
			}
			fa[x] = y;            //加入同一个集合 
			visited[e[j].u] = true;
			visited[e[j].v] = true;
			ans += e[j].cost;     
			k = j + 1;            
			break;
		}	
	}	
	
	printf("%d\n",ans);
}

int main()
{
	int n;
	int u,v,c,s;
	while(scanf("%d",&n) && n != 0)
	{
		ans = 0;
		int k = 0;
		for(int i = 0;i < n * (n - 1) / 2;i++)
		{
		    scanf("%d%d%d%d",&u,&v,&c,&s);
			if(0 == s)
			{
				e[k++] = Node(u,v,c);
			}	
			else
			{
				e[k++] = Node(u,v,0);    //0表示修建了该路,所以不需要成本 
			}
		}
		
		for(int i = 1;i <= n;i++)
		{
			fa[i] = i;
		}
		
		memset(visited,false,sizeof(visited));
		kruskal(n);
	} 
	
	
	return 0;
} 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值