某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。
输入格式:
输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。
输出格式:
输出全省畅通需要的最低成本。
输入样例:
4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0
输出样例:
3
#include <stdio.h>
#include <memory.h>
#define inf 0x3f3f3f3f
/*
全省畅通,最小生成树prim算法
这道题的关键在于有的道路是已建有的道路未建
解决方法就是:将已建的道路的成本置为0,这样在建造最小生成树时,就有花费为0的已连通的道路
*/
//prim算法也是贪心的原则,每次将到生成树的距离最小的点纳入到树中
int n,sum;
int map[101][101];
int dis[101];//表示生成的树到当前点的距离(成本)
void prim()
{
int vis[101];
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
//从1开始
for(int i=1;i<=n;i++)
{
dis[i]=map[1][i];
}
vis[1]=1;
for(int i=1;i<=n-1;i++)//成为联通图至少需要n-1条边
{
int mind=inf,minn=1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<mind)
{
mind=dis[j];
minn=j;
}
}
sum+=mind;//记下生成树每条边是值
vis[minn]=1;//找到建成最小生成树花费最小的城市minn,将minn标记为生成树成员
for(int j=1;j<=n;j++)
{
//在还没纳入树的点中查找到
if(!vis[j]&&map[minn][j]<dis[j])
{
dis[j]=map[minn][j];
}
}
}
}
int main()
{
int u,v,c,f;
scanf("%d",&n);
memset(map,inf,sizeof(map));
for(int i=1;i<=n*(n-1)/2;i++)
{
scanf("%d%d%d%d",&u,&v,&c,&f);
//这条路已建则将这条路的花费置为0
if(f==1) map[u][v]=map[v][u]=0;
else map[u][v]=map[v][u]=c;//无方向
}
prim();
printf("%d\n",sum);
return 0;
}