[图论][最短路]Restoring Road Network

题目描述

In Takahashi Kingdom, which once existed, there are N cities, and some pairs of cities are connected bidirectionally by roads. The following are known about the road network:
People traveled between cities only through roads. It was possible to reach any city from any other city, via intermediate cities if necessary.
Different roads may have had different lengths, but all the lengths were positive integers.
Snuke the archeologist found a table with N rows and N columns, A, in the ruin of Takahashi Kingdom. He thought that it represented the shortest distances between the cities along the roads in the kingdom.
Determine whether there exists a road network such that for each u and v, the integer Au,v at the u-th row and v-th column of A is equal to the length of the shortest path from City u to City v. If such a network exist, find the shortest possible total length of the roads.

Constraints
1≤N≤300
If i≠j, 1≤Ai,j=Aj,i≤109.
Ai,i=0

 

输入

Input is given from Standard Input in the following format:
N
A1,1 A1,2 … A1,N
A2,1 A2,2 … A2,N

AN,1 AN,2 … AN,N

 

输出

If there exists no network that satisfies the condition, print -1. If it exists, print the shortest possible total length of the roads.

 

样例输入

3
0 1 3
1 0 2
3 2 0

 

样例输出

3

 

提示

The network below satisfies the condition:
City 1 and City 2 is connected by a road of length 1.
City 2 and City 3 is connected by a road of length 2.
City 3 and City 1 is not connected by a road.

题意:已知任意两点间的最短路,倒推这个图
思路:emmm,一直在很认真地根据任意两点间最短路结果构建与之匹配的图。。看了别人的做法,是通过判断题给的最短路结果是否还能进行松弛操作来判断与之匹配的图是否存在,若还能进行松弛操作,则与题给最短路结果匹配的图不存在;
顺着来构建相匹配的图,(做到怀疑人生):第一个感觉是用kruscal建最小生成树,但很明显要求的图不一定是树,被否决了;然后。。就想到,边集进行排序,每加一条边前,用bfs求一下这条边两个端点间目前的最短路,和准备要加的这条边的大小比较一番blablabla;最后写完tle了,ToT;
最后想到,可以不用bfs,直接枚举中转点k来求u,v的最短路,写完wa了,ToT...;原因是“比较一番”写错了...,心好累
AC代码:
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef unsigned long long ll;
using namespace std;

ll Map[310][310];
struct Min_dis{
   int u,v;
   ll dis;
}tot[1000010];
int cnt=0;
bool cmp(Min_dis a,Min_dis b){
  return a.dis<b.dis;
}
ll edge[310][310];

int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++){
       for(int j=1;j<=n;j++){
          scanf("%llu",&Map[i][j]);
          if(i<=j) tot[++cnt].u=i, tot[cnt].v=j, tot[cnt].dis=Map[i][j];
       }
    }
    sort(tot+1,tot+1+cnt,cmp);
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) edge[i][j]=0x3f3f3f3f;
    ll ans=0;
    for(int i=1;i<=cnt;i++){
        int u=tot[i].u,v=tot[i].v;
        ll tmp=0x3f3f3f3f;
        for(int k=1;k<=n;k++){
            tmp=min(tmp,edge[u][k]+edge[k][v]);
        }
        if(tmp<tot[i].dis) {printf("-1\n"); return 0;}
        else if(tmp==tot[i].dis) {edge[u][v]=edge[v][u]=tmp; continue;}//一开始觉得在这个判断条件下不需要加边,没写edge[u][v]=edge[v][u]=tmp;其实是错的,可以看下面的样例
        else {
            ans+=tot[i].dis;
            edge[u][v]=edge[v][u]=tot[i].dis;
        }
    }
    printf("%llu\n",ans);
    return 0;
}
/*
5
0 1 5 6 8
1 0 4 5 7
5 4 0 5 3
6 5 5 0 2
8 7 3 2 0

result=15
*/

 

posted @ 2018-07-31 21:12  l..q  阅读(181)  评论(0编辑  收藏  举报