poj-1751-Highways 【prim 和 kruskal】

Description

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.

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

题意:在已有几条道路的的城市之间修一条总长最短的路

第一种: (prim )在poj上的时间是104ms,内存为 2776kb,在做最小生成树的题目要特别关注这个内存,自己做有关最小生成树的题目经常会有超内存的情况;

思路:用vis来标记所有用过的点,假设所有用过的点为一个集合  X,每次往集合 X 加入一个新点的时候,根据这个新点到所有不属于 集合X的点的距离来更新 mincost的值,然后再遍历所有的mincost,找出值最小的那个,然后把这个点放进集合X,不断执行这个循环,直到所有的点都放到集合里面,这里的mincost用一个pair类型定义,first存距离,second存当前这个点到集合X中某个点的编号;在做prim之前,把所有已经存在路径的两个城市的距离赋值为 INF,当遇到这两个点的时候,我们只需要把这个点存到队列里面,然后在更新mincost的时候,把队列的点逐个拿出来更新mincost的值就行了;下面是代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>

using namespace std;

#define Maxn 800
#define INF 0x3f3f3f3f

struct Node {
    int x,y;
} p[Maxn];

pair<int, int> mincost[Maxn];

int cost[Maxn][Maxn],V,M;
bool vis[Maxn];

int dis (int &x1, int &y1, int &x2, int &y2) {
    // 这里的距离我们只是用来比较大小的,所以只要不影响比较就行,不用开方
    return int(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

void prim () {  // 这里的prim是根据挑战程序这本书修改而来的
    for (int i = 1; i <= V; ++i) {
            vis[i] = false;
            mincost[i].first = INF;
    }
    mincost[1].first = 0; mincost[1].second = -1;
    queue<int> qu;
    
    while (1) {
        int v = -1;
        for (int u = 1; u <= V; ++u) {
            if(!vis[u] && (v == -1 || mincost[u].first < mincost[v].first)) v = u;
        }
        if(v == -1) break;
        vis[v] = 1;  qu.push(v);
        if(mincost[v].second != -1) printf("%d %d\n",v,mincost[v].second);

        while (!qu.empty()) {
            v = qu.front(); qu.pop();
            for (int u = 1; u <= V; ++u) {
                if(vis[u]) continue;
                else if(cost[u][v] == INF) { qu.push(u); vis[u] = 1; }
                else if(mincost[u].first > cost[u][v]) {
                    mincost[u].first = cost[u][v];  //更新值的同时更新终点 second
                    mincost[u].second = v;
                }
            }
        }
    }
}

int main (void)
{
    while(scanf("%d",&V) != EOF) {

        for (int i = 1; i <= V; ++i) {
            scanf("%d%d",&p[i].x,&p[i].y);
        }
        int tp;
        for (int u = 1; u < V; ++u) {
                cost[u][u] = -1;
            for (int v = u+1; v <= V; ++v) {
                tp = dis (p[u].x,p[u].y,p[v].x,p[v].y);
                cost[u][v] = tp;
                cost[v][u] = tp;
            }
        }
        int t1, t2;
        scanf("%d",&M);
        while (M--) {
            scanf("%d%d",&t1,&t2);
            cost[t1][t2] = INF;
            cost[t2][t1] = INF;
        }

        prim ();
        printf("\n");
    }
    return 0;
}

kruskal的算法比较好懂一些,把存在边的两个城市合并起来就行了,其他的就是正常的kruskal的操作;

但是时间上就差 prim一点点,因为 prim算法是 n*n的,而kruskal的算法是  Eloge的,这里的E,基本上就是n*n了,因为基本上,边就是任意两个点之间的距离,也就是n*n这个样子;

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>

using namespace std;

#define Maxn 800

struct Node {
    int x,y;
} p[Maxn];

struct Edge {
    int u,v;
    int w;
} edge[Maxn*Maxn];

bool cmp (const Edge &b1,const Edge &b2) {
    if(b1.w < b2.w) return true;
    else return false;
}

int pre[Maxn],V,M;

void make (int p) {
    pre[p] = p;
}

int Find (int x) {
    if(pre[x] != x) pre[x] = Find(pre[x]);
    return pre[x];
}

void union_ (int x, int y) {
    int xx = Find (x);
    int yy = Find (y);
    if(xx == yy) return;
    pre[xx] = yy;
}

int dis (int &x1, int &y1, int &x2, int &y2) {
    return int(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

int main (void)
{

         while(scanf("%d",&V) != EOF) {

                for (int i = 1; i <= V; ++i) {
                    scanf("%d%d",&p[i].x, &p[i].y);
                }
                int tp = 0;
                for (int i = 1; i <= V; ++i) {
                    for (int j = i + 1; j <= V; ++j) {
                        edge[tp].u = i;
                        edge[tp].v = j;
                        edge[tp].w = dis(p[i].x,p[i].y,p[j].x,p[j].y);
                        tp++;
                    }
                }
                for (int i = 1; i <= V; ++i) make(i);

                int t1,t2;
                scanf("%d",&M);
                for (int i = 0; i < M; ++i) {
                    scanf("%d%d",&t1,&t2);
                    union_(t1,t2);
                }


                sort(edge,edge+tp,cmp);

                for (int i = 0; i < tp; ++i) {
                    if(Find(edge[i].u) != Find(edge[i].v)) {
                        union_(edge[i].u,edge[i].v);
                        printf("%d %d\n",edge[i].u,edge[i].v);
                    }
                }
                printf("\n");
         }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81159041
今日推荐