POJ1751 Highways

本文介绍了一种解决道路连接问题的方法,通过最小生成树算法找到连接所有城镇的最短路径。利用C++实现该算法,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Highways
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 14819 Accepted: 4278 Special Judge

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 i th 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

Source


——————————————————————————————————————

题目的意思是给出n个坐标找出最短连接方案,把连的边输出

思路:最小生成树,先把已知边连好

注意:我用c++交wa G++交ac,不知道为什么。。。



#include <iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
#define LL long long

struct node
{
    int u,v;
    double w;
} p[10000005];
int n,m,cnt,x,pre[1000006],cc;
bool cmp(node a,node b)
{
    return a.w<b.w;
}
void init()
{
    for(int i=0; i<=n; i++)
        pre[i]=i;
}

int fin(int x)
{
    return pre[x]==x?x:pre[x]=fin(pre[x]);
}

void kruskal()
{
    sort(p,p+cnt,cmp);
    int ans=0;
    for(int i=0; i<cnt; i++)
    {
        int a=fin(p[i].u);
        int b=fin(p[i].v);
        if(a!=b)
        {
            pre[a]=b;
            ans++;
            printf("%d %d\n",p[i].u,p[i].v);
        }
        if(ans==n-cc-1)
        {
            break;
        }
    }
}


int main()
{
    double a[1005],b[1005];
    int u,v;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
            scanf("%lf%lf",&a[i],&b[i]);
        cnt=0;
        for(int i=1; i<n; i++)
            for(int j=i+1; j<=n; j++)
            {
                p[cnt].u=i,p[cnt].v=j;
                p[cnt++].w=sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]));
            }
        scanf("%d",&m);
        init();
        cc=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&u,&v);
            int a=fin(u);
            int b=fin(v);
            if(a!=b)
            {
                cc++;
                pre[a]=b;
            }
        }
        kruskal();
    }
    return 0;
}


POJ 1751是一道经典的图论问题,题目描述如下: 给定一个无向图,图中有N个节点和M条边。每条边都有一个权值。现在需要在这个图中增加最少数量的边,使得图中的任意两个节点之间都有一条路径,并且增加边的总权值最小。 这是一个典型的最小生成树(Minimum Spanning Tree, MST)问题。解决这个问题的常用算法是Kruskal算法和Prim算法。这里我们使用Kruskal算法来解决问题。 Kruskal算法的基本步骤如下: 1. 将所有边按权值从小到大排序。 2. 初始化一个并查集(Union-Find Set),将每个节点作为一个独立的集合。 3. 依次选择权值最小的边,如果这条边连接的两个节点不在同一个集合中,则将这条边加入最小生成树,并将这两个节点所在的集合合并。 4. 重复步骤3,直到所有节点都在同一个集合中,或者已经选择了N-1条边(N是节点的数量)。 下面是一个Java实现的示例代码: ```java import java.util.Arrays; import java.util.Scanner; public class Main { static int[] parent; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int M = scanner.nextInt(); Edge[] edges = new Edge[M]; parent = new int[N + 1]; for (int i = 0; i < M; i++) { int x = scanner.nextInt(); int y = scanner.nextInt(); int cost = scanner.nextInt(); edges[i] = new Edge(x, y, cost); } Arrays.sort(edges); for (int i = 1; i <= N; i++) { parent[i] = i; } int totalCost = 0; int edgeCount = 0; for (Edge edge : edges) { if (find(edge.x) != find(edge.y)) { union(edge.x, edge.y); totalCost += edge.cost; edgeCount++; if (edgeCount == N - 1) { break; } } } System.out.println(totalCost); scanner.close(); } static int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } static void union(int x, int y) { parent[find(x)] = find(y); } static class Edge implements Comparable<Edge> { int x, y, cost; Edge(int x, int y, int cost) { this.x = x; this.y = y; this.cost = cost; } @Override public int compareTo(Edge other) { return this.cost - other.cost; } } } ``` 这个代码首先读取节点和边的数量,然后读取每条边的信息并存储在Edge数组中。接着对边按权值进行排序,并初始化并查集。然后依次选择权值最小的边,如果这条边连接的两个节点不在同一个集合中,则将这条边加入最小生成树,并将这两个节点所在的集合合并。最终输出最小生成树的总权值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值