题目:
某地区经过对城镇交通状况的调查,得到现有城镇间快速道路的统计数据,并提出“畅通工程”的目标:使整个地区任何两个城镇间都可以实现快速交通(但不一定有直接的快速道路相连,只要互相间接通过快速路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建快速路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全地区畅通需要的最低成本。
输入格式:
输入的第一行给出村庄数目N (1≤N≤100);随后的N(N−1)/2行对应村庄间道路的成本及修建状态:每行给出4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态 — 1表示已建,0表示未建。
输出格式:
输出全省畅通需要的最低成本。
思路:
利用prim算法和Kruskal算法解决问题。

#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e9; #define FRE() freopen("in.txt","r",stdin) using namespace std; typedef long long ll; typedef pair<int, int> P; const int maxn = 200; int mp[maxn][maxn],w[maxn],vis[maxn]; int N; void init() { for(int i = 1; i<=N; i++) { for(int j = 1; j<=N; j++) { mp[i][j] = inf; } } int st,en,co,state,k = N*(N-1)/2; for(int i = 0; i<k; i++) { scanf("%d%d%d%d",&st,&en,&co,&state); if(state == 0) { mp[st][en] = co; mp[en][st] = co; } else { mp[st][en] = 0; mp[en][st] = 0; } } } void prim() { for(int i = 1; i<=N; i++){//从1顶点出开始生成最小生成树 vis[i] = 0; if(i != 1) w[i] = mp[1][i]; } vis[1] = 1; int pos = 0,MIN = inf; for(int i = 0; i<N; i++) { MIN = inf,pos = 0; for(int j = 1; j<=N; j++) {//从没有访问过的顶点中找到下一个距离最短的边 if(vis[j] == 0 && MIN>w[j]) { MIN = w[j]; pos = j; } } vis[pos] = 1; for(int j = 1; j<=N; j++) {//用这个最小的顶点的邻接边的权值更新w[]的值 if(!vis[j] && mp[pos][j]<w[j]) { w[j] = mp[pos][j]; } } } } void check1() { for(int i = 1; i<=N; i++) { for(int j = 1; j<=N; j++) { printf("%d ", mp[i][j]); } printf(" "); } } void check2() { for(int i = 1; i<=N; i++) { printf("%d ",w[i]); } printf(" "); } int main() { //FRE(); scanf("%d",&N); init(); prim(); //check2(); int sum = 0; for(int i = 1; i<=N; i++) { sum += w[i]; } printf("%d ",sum); return 0; } /* PutIn: 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 PutOut: 3 */

#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e9; #define FRE() freopen("in.txt","r",stdin) using namespace std; typedef long long ll; typedef pair<int, int> P; const int maxn = 5000; int vis[maxn],pre[maxn]; int N; struct edge{ int st,en,co; }e[maxn]; void init() { memset(vis,0,sizeof(vis)); for(int i = 1; i<=N; i++){//注意pre数组的初始化 pre[i] = i; } int st,en,co,state,k = N*(N-1)/2; for(int i = 0; i<k; i++) { scanf("%d%d%d%d",&st,&en,&co,&state); e[i].st = st; e[i].en = en; if(state){ e[i].co = 0; }else{ e[i].co = co; } } } int Find(int x){//查找x点的祖先 return pre[x]==x ? x : pre[x] = Find(pre[x]); } bool cmd(edge a,edge b){ return a.co<b.co; } void solve(){ int ans = 0,cnt = 0,k = N*(N-1)/2; for(int i = 0; i<k; i++){ edge te = e[i]; int tx = Find(te.st),ty = Find(te.en); if(tx!=ty){//如果两个点不在同一个集合中,就通过并查集将两个点放在一个集合中 cnt++; ans += te.co; pre[tx] = ty; } if(cnt==N-1)//当确定的边数到达规定的数量的时候,就推出循环 break; } //printf("cnt:%d ",cnt); printf("%d ",ans); } void check(){ int k = N*(N-1)/2; for(int i = 0; i<k; i++){ printf("%d ",e[i].co); } printf(" "); } int main() { //FRE(); scanf("%d",&N); init(); int k = (N-1)*N/2; sort(e,e+k,cmd);//将所有的边的权值按从小到大进行排序 //check(); solve(); return 0; } /* PutIn: 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 PutOut: 3 */