题目大意:给定n个城市,标记1-n,每个城市给定坐标,但城市间已经有一些道路,要再修路使所有城市相通并使所修的路最短,输出每一条路的编号
思路:先用并查集处理已有的路,然后prim
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX=2000000000;
struct Coor
{
int x,y;
} co[1000];
int pre[1000]= {0}; //并查集 根
int dis[1000]= {0};
int n;
int pos[1000]= {0}; //保存每个点所连接的点,输出用
queue<int> q;
int find(int x)
{
if(pre[x]!=x)
pre[x]=find(pre[x]);
return pre[x];
}
void Union(int x,int y)
{
pre[find(x)]=find(y);
}
void prim()
{
bool isin[1000]= {0};
isin[1]=1;
q.push(1);
for(int i=1; i<=n; dis[i++]=MAX);
for(int i=2; i<=n; i++) //由于集合内每一个都要对dis[]数组进行优化,我这里用队列处理
{
if(find(i)==find(1))
{
isin[i]=1;
q.push(i);
}
}
while(q.size()) //初始化dis[]数组
{
int v=q.front();
for(int i=1; i<=n; i++)
{
if(isin[i]==0)
{
int tmp=(co[v].x-co[i].x)*(co[v].x-co[i].x)+(co[v].y-co[i].y)*(co[v].y-co[i].y);
if(tmp<dis[i])
{
dis[i]=tmp;
pos[i]=v;
}
}
}
q.pop();
}
for(int j=1; j<=n; j++) //prim
{
int min=MAX,k=-1;
for(int i=1; i<=n; i++)
{
if(isin[i]==0&&dis[i]<min)
{
min=dis[i];
k=i;
}
}
if(k==-1) //结束条件,没有新点加入
break;
isin[k]=1;
q.push(k);
cout<<pos[k]<<" "<<k<<endl;
for(int i=1; i<=n; i++) //同上,队列处理
{
if(find(i)==find(k))
{
isin[i]=1;
q.push(i);
}
}
while(q.size())
{
int t=q.front();
for(int i=1; i<=n; i++)
{
if(isin[i]==0)
{
int tmp=(co[t].x-co[i].x)*(co[t].x-co[i].x)+(co[t].y-co[i].y)*(co[t].y-co[i].y);
if(tmp<dis[i])
{
dis[i]=tmp;
pos[i]=t;
}
}
}
q.pop();
}
}
}
int main()
{
for(int i=1; i<1000; pre[i]=i++);
cin>>n;
for(int i=1; i<=n; cin>>co[i].x>>co[i].y,i++);
int t;
cin>>t;
while(t--)
{
int x,y;
cin>>x>>y;
Union(x,y);
}
prim();
}