题目链接:点击查看
题目大意:有 n 个城市由 n - 1 条边连接成一个连通块,给出一个 n * n 的距离矩阵,代表 n 个城市中每两个城市之间的最短路,问该矩阵是否合法,如果合法从小到大输出 n - 1 条边
题目分析:比赛的时候没反应过来这个题的题意是想干什么,补题的时候发现原来就是一个最小生成树,因为 n 个点由 n - 1 条边组成了联通块,很显然是一棵树,题目又说了需要显示城市之间的最短距离,这就暗示了这棵树就是 n 个城市的最小生成树,现在给出的矩阵是否合法,我们只需要先判断一下是否对称(废话),然后再利用这个矩阵建边然后跑出最小生成树,利用这个最小生成树跑一遍 Floyd ,最后与原距离矩阵比较一下是否相同就可以判断是否合法了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=510;
struct Edge
{
int u,v,w;
Edge(int u,int v,int w):u(u),v(v),w(w){}
bool operator<(const Edge& a)const
{
return w<a.w;
}
};
vector<Edge>edge;
vector<int>ans;
int maze[N][N],dis[N][N],f[N];
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
bool merge(int x,int y)
{
int xx=find(x);
int yy=find(y);
if(xx!=yy)
{
f[xx]=yy;
return true;
}
return false;
}
int main()
{
//#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
//#endif
// ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&maze[i][j]);
dis[i][j]=i==j?0:inf;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
edge.push_back(Edge(i,j,maze[i][j]));
if(maze[i][j]!=maze[j][i])
return 0*printf("No");
}
sort(edge.begin(),edge.end());
for(auto it:edge)
{
if(merge(it.u,it.v))
{
ans.push_back(it.w);
dis[it.u][it.v]=dis[it.v][it.u]=it.w;
}
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(maze[i][j]!=dis[i][j])
return 0*printf("No");
puts("Yes");
for(auto it:ans)
printf("%d\n",it);
return 0;
}