nwerc2013 A-Absurdistan Roads (最小生成树(kruskal)+最短路(floyd))

Absurdistan Roads

Time Limit: 5678/3456MS (Java/Others)     Memory Limit: 65432/65432KB (Java/Others)
Submit  Status

The people of Absurdistan discovered how to build roads only last year. After the discovery, every city decided to build their own road connecting 

their city with another city. Each newly built road can be used in both directions.

Absurdistan is full of surprising coincidences. It took all N cities precisely one year to build their roads. And even more surprisingly, in the end it was 

possible to travel from every city to every other city using the newly built roads.

You bought a tourist guide which does not have a map of the country with the new roads. It only contains a huge table with the shortest distances

 between all pairs of cities using the newly built roads. You would like to know between which pairs of cities there are roads and how long they are,

 because you want to reconstruct the map of the N newly built roads from the table of shortest distances.

You get a table of shortest distances between all pairs of cities in Absurdistan using the N roads built last year. From this table, you must 

reconstruct the road network of Absurdistan. There might be multiple road networks with N roads with that same table of shortest distances, 

but you are happy with any one of those networks.

Input

For each test case:

  • A line containing an integer N (2N2000) -- the number of cities and roads.
  • N lines with N numbers each. The j-th number of the i-th line is the shortest distance from city i to city j. All distances between two
  •  distinct cities will be positive and at most 1000000
  • The distance from i to i will always be 0 and the distance from i to j will be the same as the distance from j to i.

Output

For each test case:

  • Print N lines with three integers 'a b c' denoting that there is a road between cities 1aN and 1bN of length 1c1000000
  • where ab. If there are multiple solutions, you can print any one and you can print the roads in any order. At least one solution is 
  • guaranteed to exist.

Print a blank line between every two test cases.

Sample input and output

Sample Input Sample Output
4
0 1 2 1
1 0 2 1
2 2 0 1
1 1 1 0
4
0 1 1 1
1 0 2 2
1 2 0 2
1 2 2 0
3
0 4 1
4 0 3
1 3 0
2 1 1
4 1 1
4 2 1
4 3 1

2 1 1
3 1 1
4 1 1
2 1 1

3 1 1
2 1 4
3 2 3

Source

Northwestern European Regional Contest 2013

题意:给你一个邻接矩阵代表最短路的情况,让你给出n条原始的边,使得这个最短路成立。

方法:要找的都是必要的边。先构造1棵最小生成树,这n-1条边是部分答案,然后是找最后一条边。用floyd求出任意两点间的距离,

找出未满足最短距离并且这两个点的最短距离最小的边,如果都已满足最短距离则随意添加一条重边即可。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

struct Edge
{
    int u,v,len;
}edge[4000005];

int dist[2005],mp[2005][2005];
int father[2005];
int N,num;

int cmp(Edge a,Edge b)
{
    return a.len<b.len;
}

void init(int n)
{
    memset(mp,INF,sizeof(mp));
    for (int i=1;i<=n;i++)
        father[i]=i;
}

int find_father(int x)
{
    if (x!=father[x])
        father[x]=find_father(father[x]);
    return father[x];
}

void Kruskal()
{
    int i,j,sum=0;
    init(N);
    for (i=0;i<num;i++)
    {
        int fa=find_father(edge[i].u);
        int fb=find_father(edge[i].v);
        if (fa!=fb)
        {
            father[fa]=fb;
            mp[ edge[i].u ][ edge[i].v ]=mp[ edge[i].v ][ edge[i].u ]=edge[i].len;
            printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].len);
            sum++;
            if (sum>=N-1)
                break;
        }
    }
}

void floyd()
{
    int i,j,k;
    for (k=1;k<=N;k++)
        for (i=1;i<=N;i++)
            for (j=1;j<=N;j++)
            {
                if (mp[i][k]==INF)
                    break;
                mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
            }
}

int main()
{
    int i,j,flag=0;
    while (~scanf("%d",&N))
    {
        num=0;
        int w;
        if (flag)
            printf("\n");
        flag=1;
        for (i=1;i<=N;i++)
            for (j=1;j<=N;j++)
            {
                scanf("%d",&w);
                if (i<=j)
                    continue;
                edge[num].u=i;
                edge[num].v=j;
                edge[num++].len=w;
            }
        sort(edge,edge+num,cmp);
        Kruskal();
        floyd();
        for (i=0;i<num;i++)
        {
            if (edge[i].len!=mp[ edge[i].u ][ edge[i].v ])
            {
                printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].len);
                break;
            }
        }
        if (i==num)
            printf("%d %d %d\n",edge[0].u,edge[0].v,edge[0].len);
    }
    return 0;
}
/*
4
0 1 2 1
1 0 2 1
2 2 0 1
1 1 1 0
4
0 1 1 1
1 0 2 2
1 2 0 2
1 2 2 0
3
0 4 1
4 0 3
1 3 0
*/



转载于:https://www.cnblogs.com/i8888/p/4044022.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值