Connect the Cities
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10692 Accepted Submission(s): 3037
Problem Description
In 2100, since the sea level rise, most of the cities disappear. Though some survived cities are still connected with others, but most of them become disconnected. The government wants to build some roads to connect all of these cities
again, but they don’t want to take too much money.
Input
The first line contains the number of test cases.
Each test case starts with three integers: n, m and k. n (3 <= n <=500) stands for the number of survived cities, m (0 <= m <= 25000) stands for the number of roads you can choose to connect the cities and k (0 <= k <= 100) stands for the number of still connected
cities.
To make it easy, the cities are signed from 1 to n.
Then follow m lines, each contains three integers p, q and c (0 <= c <= 1000), means it takes c to connect p and q.
Then follow k lines, each line starts with an integer t (2 <= t <= n) stands for the number of this connected cities. Then t integers follow stands for the id of these cities.
Output
For each case, output the least money you need to take, if it’s impossible, just output -1.
Sample Input
1 6 4 3 1 4 2 2 6 1 2 3 5 3 4 33 2 1 2 2 1 3 3 4 5 6
Sample Output
1
Author
dandelion
Source
HDOJ Monthly Contest – 2010.04.04
考察知识点:
最小生成树。
题目难点:如何判断-1 出现的情况。怎么将已经连通的路径标记。
解决办法:出现-1 的情况,无非就是两条路之间没有连接,即距离无法判断。那么在最小生成树中的prime算法中,可以通过比较确定一个顶点的最小值,来判断是否有孤立的点(即既无法构建道路,也没有与其他顶点相连接的路径),要是有的话,就说明没有无法连通,满足-1出现的情况。对已经连通的路径可以通过将其权值赋值为0,来进行标记,在选择最小权值 的时候,就会将其他的路径略去。
代码如下:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int map[550][550]; int visit[550]; int n; void prime() { int i,j,sum=0,min,k; memset(visit,0,sizeof(visit)); visit[1]=1; for(i=1;i<n;i++)//共需要构建n-1条边,所以共要循环n-1次 { min=1000; for(j=1;j<=n;j++)//n个顶点 { if(!visit[j]&&min>map[1][j]) { min=map[1][j]; k=j; } } if(min==1000)//要是有连通的边则min就会发生相应的变化 { break; } sum+=min; visit[k]=1; for(j=1;j<=n;j++) { if(!visit[j]&&map[1][j]>map[k][j]) map[1][j]=map[k][j]; } } if(min==1000) printf("-1\n"); else printf("%d\n",sum); } int main() { int num,m,k,p,q,c,t,i,j,a,b; scanf("%d",&num); while(num--) { //memset(map,1000,sizeof(map));//memset函数看来是有范围的只能对数组进行1,或者是0,的赋值,其他则没有办法赋值。 scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++)//数组初始化 { for(j=1;j<=n;j++) { map[i][j]=1000; } } for(i=0;i<m;i++) { scanf("%d%d%d",&p,&q,&c);//注意需要考虑重边的情况。 map[p][q]=map[p][q]>c?c:map[p][q]; map[q][p]=map[p][q]; } for(i=0;i<k;i++) { scanf("%d%d",&t,&a); for(j=t-1;j>0;j--) { scanf("%d",&b); map[a][b]=map[b][a]=0; } } prime(); } return 0; }