題目鏈接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66965#problem/H
題意:修高速公路問題,求最小連通造價,但是會給出一些已經修好了的邊,求需要修剪的邊。
思路:這題和POJ 2412 Constructing Roads差不多,用Kruskal逐條加邊,只是把Kruskal的求sum值改成存儲邊值就好了。
代碼:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct edge{
int u,v,w;
bool operator <(const edge&a)const{
return w<a.w;
}
}E[600000];
int N,M,tot,X[800],Y[800];
int vis[751][751],pre[800];
vector<int> ans;
int find(int x){
int t=x;
while(t!=pre[t]) t=pre[t];
while(x!=t) pre[x]=t,x=pre[x];
return t;
}
void Kruskal(){
ans.clear();
for(int i=0;i<tot;i++){
int fu=find(E[i].u),fv=find(E[i].v);
if(fu==fv) continue;
pre[fv]=fu;ans.push_back(i);//把求和改成路徑就好了
}
for(int i=0;i<ans.size();i++){
int k=ans[i];
cout<<E[k].u<<" "<<E[k].v<<endl;
}
}
int main(){
//freopen("D:\\in.txt","r",stdin);
while(cin>>N){
for(int i=1;i<=N;i++) scanf("%d %d",X+i,Y+i);
memset(vis,0,sizeof(vis));
for(int i=0;i<=N;i++) pre[i]=i;
cin>>M;
int a,b;
for(int i=0;i<M;i++){
scanf("%d %d",&a,&b);
vis[a][b]=vis[b][a]=1;
pre[find(b)]=find(a);
}
tot=0;
for(int i=1;i<=N;i++) for(int j=1;j<i;j++) if(!vis[i][j]){
int t=(X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]);
E[tot++]=(edge){i,j,t};
}
if(tot==0) {cout<<endl;continue;}
sort(E,E+tot);
Kruskal();
}
return 0;
}