0)
题意:已经在部分城市之间建造了道路,求再花费多少钱建造道路使得所有城市连通。
求连接所有点的最小花费,这是最小生成路问题,变形在于已经修建好了部分道路。之前的思路是,在所有未连接的点图中,如何构建出所有需要的道路,而在构建之前如何将已经修好的路放进去,事实上这样的思想不明确也不简洁。好的做法是将修好的道路的修建花费直接赋值为0。然后就可以直接上最小生成树的模板,Prim或者Kruskal都可以。这么来看的话,这个题也是比较裸的。
(Prim从点出发更适合稠密图,Kruskal从边出发更适合稀疏图)
1)
Prim
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int maxn=110; const int INF=0x3f3f3f3f; int mat[maxn][maxn]; int dis[maxn]; int used[maxn]; int sum=0; void Prim(int n){ int cur=1; used[cur]=1; for(int i=1;i<=n;i++){ dis[i]=mat[cur][i]; } for(int i=1;i<n;i++){ int cur_min=INF; int temp=-1; for(int j=1;j<=n;j++){ //if(cur==j) continue;之前因为cur写成了i所以wa,实际上这一句话不用写 if(used[j]==0&&cur_min>dis[j]){ cur_min=dis[j]; temp=j; } } if(temp==-1){ break; } sum+=cur_min; cur=temp; used[cur]=1; for(int j=1;j<=n;j++){ if(used[j]==0) dis[j]=min(dis[j],mat[cur][j]);//更新确定集合,到j点的最小距离 } } } int main() { int n; while(~scanf("%d",&n)){ memset(mat,0,sizeof(mat)); memset(used,0,sizeof(used)); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&mat[i][j]); } } int q; //int coun=0; scanf("%d",&q); while(q--){ int l,r; scanf("%d%d",&l,&r); mat[l][r]=0;//精妙所在 mat[r][l]=0; } sum=0; memset(dis,INF,sizeof(dis)); Prim(n); cout<<sum<<endl; } return 0; }
Kruskal
......
2)
Description
Input
Output
Sample Input
3 0 990 692 990 0 179 692 179 0 1 1 2
Sample Output
179