Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为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;
}