1. 程式人生 > 實用技巧 >I - I(Highways)

I - I(Highways)

N個點,給你N個點的座標,現在還有Q條邊已經連線好了。問把N個點怎麼連線起來的花費的距離最短? The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of public highways. The Flatopian government is aware of this problem and has already constructed a number of highways connecting some of the most important towns. However, there are still some towns that you can't reach via a highway. It is necessary to build more highways so that it will be possible to drive between any pair of towns without leaving the highway system.

Flatopian towns are numbered from 1 to N and town i has a position given by the Cartesian coordinates (xi, yi). Each highway connects exaclty two towns. All highways (both the original ones and the ones that are to be built) follow straight lines, and thus their length is equal to Cartesian distance between towns. All highways can be used in both directions. Highways can freely cross each other, but a driver can only switch between highways at a town that is located at the end of both highways.

The Flatopian government wants to minimize the cost of building new highways. However, they want to guarantee that every town is highway-reachable from every other town. Since Flatopia is so flat, the cost of a highway is always proportional to its length. Thus, the least expensive highway system will be the one that minimizes the total highways length.

Input

The input consists of two parts. The first part describes all towns in the country, and the second part describes all of the highways that have already been built.

The first line of the input file contains a single integer N (1 <= N <= 750), representing the number of towns. The next N lines each contain two integers, xi and yi separated by a space. These values give the coordinates of ith
town (for i from 1 to N). Coordinates will have an absolute value no greater than 10000. Every town has a unique location.

The next line contains a single integer M (0 <= M <= 1000), representing the number of existing highways. The next M lines each contain a pair of integers separated by a space. These two integers give a pair of town numbers which are already connected by a highway. Each pair of towns is connected by at most one highway.

Output

Write to the output a single line for each new highway that should be built in order to connect all towns with minimal possible total length of new highways. Each highway should be presented by printing town numbers that this highway connects, separated by a space.

If no new highways need to be built (all towns are already connected), then the output file should be created but it should be empty. Flatopia島國完全平坦。不幸的是,Flatopia的公共高速公路系統非常糟糕。弗拉託利亞政府意識到了這個問題,並且已經建造了一些連線一些最重要城鎮的高速公路。但是,仍有一些城鎮無法通過高速公路抵達。有必要建造更多的高速公路,以便能夠在不離開高速公路系統的情況下在任何一對城鎮之間行駛。
Flatopian城鎮的編號從1到N,城鎮i的位置由笛卡爾座標(xi,yi)給出。每條高速公路連線兩個城鎮。所有高速公路(原始高速公路和要建造的高速公路)都遵循直線,因此它們的長度等於城鎮之間的笛卡爾距離。所有高速公路都可以在兩個方向上使用。高速公路可以自由地相互交叉,但司機只能在位於兩條高速公路盡頭的小鎮的高速公路之間切換。
Flatopian政府希望最大限度地降低建設新高速公路的成本。但是,他們希望保證每個城鎮都可以從其他城鎮到達公路。由於Flatopia是如此平坦,高速公路的成本總是與其長度成正比。因此,最便宜的高速公路系統將是最小化總公路長度的系統。

Sample Input

9
1 5
0 0 
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3
1 3
9 7
1 2

Sample Output

1 6
3 7
4 9
5 7
8 3
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define inf 0x7fffffff
int dp[1010][1010],vis[1010],dis[1010],f[1010];
int x[1010],y[1010],m,n;
void djk()
{
    int i,j;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        dis[i]=dp[1][i];//假設所有城鎮都是與1號城鎮連線最優;其實和dis陣列一個意思,後面也一樣更新
        f[i]=1;
    }
    dis[1]=0;
    vis[1]=1;
    for(int i=1;i<=n;i++)
    {
        int k=0,minn=inf;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&minn>dis[j])
            {
                minn=dis[j];
                k=j;
            }
        }
        vis[k]=1;
        if(dp[f[k]][k]!=0) //輸出所有距離不為0相連的城鎮即為需要建設的道路
            printf("%d %d\n",k,f[k]);//不是已經建好的路就輸出當前建立的邊
        for(int j=1;j<=n;j++)
        {
            if(!vis[j]&&dis[j]>dp[k][j])
            {
                dis[j]=dp[k][j];//當有更優的路線到v城鎮更新距離,更新與v城鎮相連的城鎮號
                f[j]=k;
            }
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        int i,j,a,b;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            for(int j=1;j<=i;j++)
                dp[i][j]=dp[j][i]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            dp[a][b]=dp[b][a]=0;//城鎮間已有公路距離為0
        }
        djk();
    }
}

方法2:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct A
{
    int a;
    int b;
    double c;
}q[1000010];
double cmp(struct A x,struct A y)
{
    return x.c<y.c;
}
int f[10010],a[10010],b[10010];
int getf(int i)
{
    if(f[i]==i)
        return i;
    else
    {
        f[i]=getf(f[i]);
        return f[i];
    }
}
int merge(int v,int u)
{
    int t1,t2;
    t1=getf(u);
    t2=getf(v);
    if(t1!=t2)
    {
        f[t1]=t2;
        return 1;
    }
    return 0;
}
 
int main()
{
    int n,m,x,y,i,j,v,t,cut;
    scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d%d",&a[i],&b[i]);
        v=1;
        for(i=1;i<n;i++)//儲存路徑 
            for(j=i+1;j<=n;j++)
            {
                q[v].a=i;
                q[v].b=j;
                q[v].c=(double)sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]));
                v++;
            }
        v=v-1;
        sort(q+1,q+v+1,cmp);
        for(i=1;i<=n;i++)
            f[i]=i;
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            merge(x,y);//查詢是否為共同祖先,賦給共同祖先 
        }
        cut=0;
        for(i=1;i<=v;i++)
        {
            if(merge(q[i].a,q[i].b))//若不是一個共同祖先說明兩城鎮間未連線為需要建設的城鎮 
            {                        //儲存兩城鎮 
                a[cut]=q[i].a;
                b[cut]=q[i].b;
                cut++;
            }
            if(cut==n-1)//這個判斷只是為了提前結束迴圈,不加也能AC 
                break;
        }
        for(i=0;i<cut;i++)
            printf("%d %d\n",a[i],b[i]);
    return 0;
}