Time Limit: 2000MS | Memory Limit: 65536K | |
Description
Input
Output
Sample Input
3 0 990 692 990 0 179 692 179 0 1 1 2
Sample Output
179
Source
找的最小生成树专题里的一个题,看到这题却发现和河南省第八届省赛的“引水工程”惊人的相似,反正那道题也没做出来,本打算先A了那道题再做这道题,可是做了那题之后又发现这道题还更简单,于是调调代码直接A了,其实我宁愿相信是后台测试数据水的;
来说说思路吧:我们发现输入是以矩阵的模式,如果全部存在结构体中无疑是浪费内存,我们发现这个矩阵中很多相同的数,即坐标相对应的点(如a[i][j]=a[j][i])的值是一样的,所以只需要把矩阵中的一半的数存在结构体中就可以了,然后就是最简单的最小生成树了,至于有Q条已经联通好的路我们只需在输入得时候利用并查集将输入的数据的根节点合并即可;可能这里表达有点不清楚,来看代码就马上明白了;
AC代码:说白了,这题就是并查集与最小生成树的灵活运用;
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=5100;//数据范围是100,平方是10000,但Q<=10000/2,开5050就可以过了; int n,m,k,f[100]; struct node { int u,v,w; } a[N]; int cmp(node a,node b) { return a.w<b.w; } int find(int x) { return f[x]==-1?x:x=find(f[x]); } int ks(int n) { int ans=0,cot=0; sort(a+1,a+1+k,cmp); for(int i=1; i<=k; i++) { int u=find(a[i].u); int v=find(a[i].v); if(u!=v) { ans+=a[i].w; f[u]=v; cot++; } if(cot==n-1) break; } return ans; } int main() { int x; scanf("%d",&n); k=0; memset(a,0,sizeof(a)); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) { scanf("%d",&x); if(j>i)//把一半的数据存在结构体中; a[++k].u=i,a[k].v=j,a[k].w=x; } memset(f,-1,sizeof(f)); scanf("%d",&m); int x1,y1; while(m--) { scanf("%d%d",&x1,&y1); int xx=find(x1); int yy=find(y1); if(xx!=yy)//根节点合并->并查集; { f[xx]=yy; n--; } } printf("%d\n",ks(n)); return 0; }