Highways
题意:
给定一个整数 n,表示有 n 个城镇,编号为1~n,接下来 n 行是各个城镇的坐标,然后给定一个整数 m ,表示已修建好的路,接下来 m 行,每行两个整数,分别是已修建好的路连通的两个城镇,找出一条单线使得所有城镇与公路总长度尽可能短的连接起来,每一条公路都应该打印出该公路连接的城镇编号,并用空格隔开。若所有城镇都已连通,则输出为空(换行)。
数据范围:
N (1 <= N <= 750),M (0 <= M <= 1000),坐标大小<=10000
解题思路:
Prim 算法
代码:
Memory: 4604K | Time: 110MS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;
#define INF 0x3f3f3f
#define zero 1e-7
typedef long long ll;
const int N=755;
double mp[N][N], w[N];
int x[N], y[N], dis[N];
bool vis[N];
void build(int n) {
for(int i=1; i<=n; i++) {
for(int j=i; j<=n; j++) {
double d=sqrt((double)((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
mp[i][j]=mp[j][i]=d;
}
}
return ;
}
void prim(int n) {
memset(vis, false, sizeof(vis));
vis[1]=true;
for(int i=1; i<=n; i++) {
w[i]=mp[1][i];
dis[i]=1;
}
for(int i=1; i<n; i++) {
double mind=INF;
int temp;
for(int j=2; j<=n; j++) {
if(w[j]<mind && !vis[j]) {
mind=w[j];
temp=j;
}
}
vis[temp]=true;
if(mind)
printf("%d %d\n", dis[temp], temp);
for(int j=2; j<=n; j++) {
if(mp[temp][j]<w[j] && !vis[j]) {
w[j]=mp[temp][j];
dis[j]=temp;
}
}
}
}
int main() {
int n, m, a, b;
scanf("%d", &n);//居然只有一组输入o(╥﹏╥)o
for(int i=1; i<=n; i++)
scanf("%d %d", &x[i], &y[i]);
build(n);
scanf("%d", &m);
while(m--) {
scanf("%d %d", &a, &b);
mp[a][b]=mp[b][a]=0;
}
prim(n);
}
不晓得为啥,用 Kruskal 算法写的 TLE 了,本来一开始是觉得用 Prim 写比较合适,但是因为误以为是多组输入,写成了 while(scanf("%d", &n)!=EOF)
,所以就改用 Kruskal 写了,还是 TLE ,后来发现是一组输入后就改了过来,结果还是 TLE ,绝望之际把原来用 Prim 写的改了一下提交,谢天谢地终于 AC 了(╥╯﹏╰╥)ง,决定还是把用 Kruskal 写的 TLE 的代码附上,说不定日后能看出什么端倪。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;
#define INF 0x3f3f3f
#define zero 1e-7
typedef long long ll;
const int N=755;
double mp[N][N];
int x[N], y[N];
int par[N];
struct node {
int from, to;
double w;
}edge[N*N/2];
bool cmp(node a, node b) {
return a.w<b.w;
}
void build(int n) {
for(int i=1; i<n; i++) {
for(int j=i+1; j<=n; j++) {
double d=sqrt((double)((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
mp[i][j]=d;
}
}
return ;
}
void init(int n) {
for(int i=1; i<=n; i++)
par[i]=i;
return ;
}
int find(int a) {
if(a==par[a]) return a;
else return par[a]=find(par[a]);
}
void kruskal(int cnt, int n) {
sort(edge, edge+cnt, cmp);
//for(int i=0; i<=n; i++) printf("%d-%d: edge[%d]=%lf\t", edge[i].from, edge[i].to, i, edge[i].w);
bool flag=false;
for(int i=0; i<cnt; i++){//需要连通的边数为n
int a=find(edge[i].from);
int b=find(edge[i].to);
//printf("a=%d, b=%d\t", a, b);
if(a!=b) {
par[b]=a;
n--;
if(edge[i].w>0) {
printf("%d %d\n", edge[i].from, edge[i].to);
flag=true;
}
}
if(!n) break;
}
if(!flag) printf("\n");
}
int main() {
int n, m, a, b, cnt;
scanf("%d", &n);
cnt=0;
init(n);
for(int i=1; i<=n; i++)
scanf("%d %d", &x[i], &y[i]);
build(n);
scanf("%d", &m);
while(m--) {
scanf("%d %d", &a, &b);
mp[a][b]=mp[b][a]=0;
}
for(int i=1; i<n; i++) {
for(int j=i+1; j<=n; j++) {
edge[cnt].from=i;
edge[cnt].to=j;
edge[cnt++].w=mp[i][j];
}
}
kruskal(cnt, n-1);
}