时间限制: 1 Sec 内存限制: 128 MB
题目描述
从前有一张n个点的无向图,边权都是正整数。但现在所有的边都消失了,只留下任意两点之间的最短路。
你现在想知道,所有边的边权和至少是多少。
输入
第一行一个正整数n 。
接下来一个n×n的矩阵A ,其中Ai,j代表原来图中i到j的最短路。
保证Ai,i=0,Ai,j=Aj,i。
输出
一行一个整数,表示答案。
如果不存在任何连边方案满足所有的最短路限制,输出-1 。
样例输入
3
0 1 3
1 0 2
3 2 0
样例输出
3
提示
对于30%的数据,n≤7。
对于另外30%的数据,保证存在一种最优解,满足原图是一条链。
对于100%的数据,满足n≤300,1≤Ai,j≤109,(i≠j) 。
思路
判断dis[ i ] [ j ]与dis[ i ] [ k ] + dis[ k ] [ j ]的关系。
如果dis[ i ] [ j ] > dis[ i ] [ k ] + dis[ k ] [ j ] ,说明不满足任何连边方案满足所有的最短路限制,输出 - 1。
如果等于就说明这条边是可以省略删去的,标记一下。
最后将所有未标记的边加起来,结果除以2(因为正反加了两遍)
代码:
#include<iostream>
#include<string>
#include<map>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
typedef long long ll;
const double eps=0.01;
const int N=310;
const int mod=1000000007;
ll ans,dis[N][N],n;
bool vis[N][N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&dis[i][j]);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(k==i||i==j||k==j) continue;
if(dis[i][j]>dis[i][k]+dis[k][j])
{
printf("-1");
return 0;
}
if(dis[i][j]==dis[i][k]+dis[k][j]) vis[i][j]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(!vis[i][j])
{
ans+=dis[i][j];
}
}
printf("%lld",ans/2);
return 0;
}