3 0 990 692 990 0 179 692 179 0 1 1 2
179
这道题的思路就是求最小生成树。详见AC code 的注释
先贴一个WA的代码,这个代码的bug让我查了两天,最后才茅塞顿开。。。
#include <iostream> #include <cstdio> #include <cstdlib> #define max 0x7fffffff using namespace std; struct edge { int v1; int v2; int w; }e[6000]; int cmp(const void *a,const void *b) { struct edge *aa=(struct edge *)a; struct edge *bb=(struct edge *)b; if(aa->w != bb->w) return aa->w - bb->w; else return aa->v1 - bb->v1; } int main() { int n,q,a,b,map[101][101],vis[101],i,j,k,min; while(scanf("%d",&n)!=EOF) { min=0; for(i=1;i<=n;i++) vis[i]=i; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&map[i][j]); } map[i][i]=max; } scanf("%d",&q); for(i=1;i<=q;i++) { scanf("%d%d",&a,&b); map[a][b]=map[b][a]=0; vis[b]=vis[a];//连通的两点标记相同,修改数值大的顶点使之与小的顶点相同,bug就在这里 } for(i=1,k=1;i<=n;i++) { for(j=1;j<=i;j++) { e[k].v1=i; e[k].v2=j; e[k].w=map[i][j]; k++; } } qsort(&e[1],k-1,sizeof(e[1]),cmp); //j记录生成树中的边数,边数最终要等于n-1 for(i=1,j=q;j<n-1;i++) { if(vis[e[i].v1] != vis[e[i].v2]) { int m=vis[e[i].v1]>vis[e[i].v2] ? vis[e[i].v2] : vis[e[i].v1]; int M=vis[e[i].v1]>vis[e[i].v2] ? vis[e[i].v1] : vis[e[i].v2]; for(int ii=1;ii<=n;ii++) { if(vis[ii]==M) vis[ii]=m; } min+=e[i].w; j++; } } printf("%d\n",min); } return 0; }
AC code(15ms)
#include <iostream> #include <cstdio> #include <cstdlib> #define max 0x7fffffff using namespace std; struct edge { int v1; int v2; int w; }e[6000];//储存边 int cmp(const void *a,const void *b) { struct edge *aa=(struct edge *)a; struct edge *bb=(struct edge *)b; if(aa->w != bb->w) return aa->w - bb->w; else return aa->v1 - bb->v1;//当权值相同时按顶点排序 } int main() { int n,q,a,b,map[101][101],vis[101],i,j,k,min;//map记录邻接矩阵,vis为顶点设置标志 while(scanf("%d",&n)!=EOF) { min=0; for(i=1;i<=n;i++) vis[i]=i;//初始化vis,使各个顶点开始时各自属于独立的集合 //输入邻接矩阵 for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scanf("%d",&map[i][j]); } map[i][i]=max;//自己到自己的路径修改为max } //输入已修好的路径 scanf("%d",&q); for(i=1;i<=q;i++) { scanf("%d%d",&a,&b); map[a][b]=map[b][a]=0; //vis[b]=vis[a]; } //将边的信息存入结构体e,注意只需存下三角形 for(i=1,k=1;i<=n;i++) { for(j=1;j<=i;j++) { e[k].v1=i; e[k].v2=j; e[k].w=map[i][j]; k++; } } //快排,因为从e[1]开始储存,故从e[1]开始排序 qsort(&e[1],k-1,sizeof(e[1]),cmp); //生成树 for(i=1,j=1;j<n;i++) { //两个顶点属于不同集合时表明边尚未加入树中 if(vis[e[i].v1] != vis[e[i].v2]) { //修改数值大的顶点的标志及其所有祖先的标志,将他们纳入树中 int m=vis[e[i].v1]>vis[e[i].v2] ? vis[e[i].v2] : vis[e[i].v1]; int M=vis[e[i].v1]>vis[e[i].v2] ? vis[e[i].v1] : vis[e[i].v2]; for(int ii=1;ii<=n;ii++) { if(vis[ii]==M) vis[ii]=m; } min+=e[i].w; j++; } } printf("%d\n",min); } return 0; }