最小生成树的水题,直接的最小生成树算法就可以了。题意给定n个城市,只不过是又给定了已经连接起来的道路,由于输出的是城镇的编号,所以不用计算两城镇之间的真正距离(既不用算sqrt),用的是kruskal,比较费时,估计用prim可以节省不少时间.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <memory.h>
using namespace std;
const int MAXN = 800;
const int MAXE = 500000;
const int INF = 0x7fffffff;
int nv,ne,index,set[MAXN],pos[MAXE];
struct Edge{
int u,v;
int val;
}edge[MAXE];
struct Node{
int x,y;
}node[MAXN];
int cmp(const Edge& a,const Edge& b)
{
return a.val < b.val;
}
int find_set(int x)
{
int root = x,tmp;
while(set[root] >= 0)
root = set[root];
while( x != root)
{
tmp = set[x];
set[x] = root;
x = tmp;
}
return root;
}
void union_set(const int& root1,const int& root2)
{
int a = set[root1];
int b = set[root1];
if( a>b)
{
set[root1] = root2;
set[root2] += a;
}else{
set[root2] = root1;
set[root1] += b;
}
}
int kruskal()
{
index = 0;
int sum = 0,root1,root2,tmp,i;
for(i = 0;i < ne; ++i)
{
root1 = find_set(edge[i].u);
root2 = find_set(edge[i].v);
if( root1 != root2)
{
pos[index] = i;
++index;
union_set(root1,root2);
}
}
return sum;
}
int main()
{
int i,j,k,a,b,tmp,val,n,m,root1,root2;
while(scanf("%d",&nv) != EOF)
{
memset(set,-1,sizeof(set));
for(i = 1;i <= nv; ++i)
scanf("%d%d",&(node[i]).x,&(node[i].y));
index = 0;
for(i = 1;i <= nv; ++i)
for(j = i + 1;j <= nv; ++j)
{
edge[index].u = i;
edge[index].v = j;
edge[index].val = (node[i].x-node[j].x)*(node[i].x-node[j].x)+
(node[i].y - node[j].y)*(node[i].y-node[j].y);
++index;
}
ne = index;
sort(edge,edge+ne,cmp);
scanf("%d",&n);
for(i = 1;i <= n; ++i)
{
scanf("%d%d",&a,&b);
root1 = find_set(a);
root2 = find_set(b);
if( root1 != root2)
union_set(root1,root2);
}
kruskal();
for(i = 0;i < index; ++i)
printf("%d %d\n",edge[pos[i]].u,edge[pos[i]].v);
}
return 0;
}
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <memory.h>
using namespace std;
const int MAXN = 800;
const int MAXE = 500000;
const int INF = 0x7fffffff;
int nv,ne,index,set[MAXN],pos[MAXE];
struct Edge{
int u,v;
int val;
}edge[MAXE];
struct Node{
int x,y;
}node[MAXN];
int cmp(const Edge& a,const Edge& b)
{
return a.val < b.val;
}
int find_set(int x)
{
int root = x,tmp;
while(set[root] >= 0)
root = set[root];
while( x != root)
{
tmp = set[x];
set[x] = root;
x = tmp;
}
return root;
}
void union_set(const int& root1,const int& root2)
{
int a = set[root1];
int b = set[root1];
if( a>b)
{
set[root1] = root2;
set[root2] += a;
}else{
set[root2] = root1;
set[root1] += b;
}
}
int kruskal()
{
index = 0;
int sum = 0,root1,root2,tmp,i;
for(i = 0;i < ne; ++i)
{
root1 = find_set(edge[i].u);
root2 = find_set(edge[i].v);
if( root1 != root2)
{
pos[index] = i;
++index;
union_set(root1,root2);
}
}
return sum;
}
int main()
{
int i,j,k,a,b,tmp,val,n,m,root1,root2;
while(scanf("%d",&nv) != EOF)
{
memset(set,-1,sizeof(set));
for(i = 1;i <= nv; ++i)
scanf("%d%d",&(node[i]).x,&(node[i].y));
index = 0;
for(i = 1;i <= nv; ++i)
for(j = i + 1;j <= nv; ++j)
{
edge[index].u = i;
edge[index].v = j;
edge[index].val = (node[i].x-node[j].x)*(node[i].x-node[j].x)+
(node[i].y - node[j].y)*(node[i].y-node[j].y);
++index;
}
ne = index;
sort(edge,edge+ne,cmp);
scanf("%d",&n);
for(i = 1;i <= n; ++i)
{
scanf("%d%d",&a,&b);
root1 = find_set(a);
root2 = find_set(b);
if( root1 != root2)
union_set(root1,root2);
}
kruskal();
for(i = 0;i < index; ++i)
printf("%d %d\n",edge[pos[i]].u,edge[pos[i]].v);
}
return 0;
}