codeforces472D

Design Tutorial: Inverse the Problem

 CodeForces - 472D 

给你了一个 n × n最短距离矩阵。(即矩阵中dis[u][v]为u点到v点的最短距离),判断是否存在一个边权皆为正整数的树,恰好满足这个最短距离矩阵 。

Input

第一行为一个整数 n (1 ≤ n ≤ 2000) — 表示图中有多少个点.

下面 n 行,每行包括 n 个整数 di, j (0 ≤ di, j ≤ 109) — 点i和点j之间的最短距离.

Output

如果存在这样的树,输出 "YES", 否则输出"NO".

Examples

Input
3
0 2 7
2 0 9
7 9 0
Output
YES
Input
3
1 2 7
2 0 9
7 9 0
Output
NO
Input
3
0 2 2
7 0 9
7 9 0
Output
NO
Input
3
0 1 1
1 0 1
1 1 0
Output
NO
Input
2
0 0
0 0
Output
NO

sol:首先很明显的性质就是在树上,两个点之间一定有且仅有一条最短的路径,于是很明显用Kruskal把MST构建出来之后暴力dfs判断距离是否相等即可
Ps:根据样例可以特判掉很多奇奇怪怪的情况,比方说Dis[x][x]!=0或者Dis[x][y]!=Dis[y][x]等等(不过对答案毫无影响)
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0'); return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=2005,M=4000005;
int n,Dis[N][N];
namespace Tree
{
    int tot=0,Next[M],to[M],val[M],head[N];
    int cnt=0;
    struct Edge
    {
        int U,V,Quan;
        inline bool operator<(const Edge &tmp)const
        {
            return Quan<tmp.Quan;
        }
    }E[M];
    inline void add(int x,int y,int z)
    {
        Next[++tot]=head[x];
        to[tot]=y;
        val[tot]=z;
        head[x]=tot;
    }
    int Father[N];
    inline int GetFa(int x)
    {
        return (Father[x]==x)?(Father[x]):(Father[x]=GetFa(Father[x]));
    }
    int Root,Path[N][N];
    inline void dfs(int x,int fa,int Sum)
    {
        int i; Path[Root][x]=Sum;
        for(i=head[x];i;i=Next[i]) if(to[i]!=fa)
        {
            dfs(to[i],x,Sum+val[i]);
        }
    }
    inline void Solve()
    {
        int i,j;
        for(i=1;i<=n;i++)
        {
            Father[i]=i;
            for(j=1;j<i;j++) E[++cnt]=(Edge){j,i,Dis[j][i]};
        }
        sort(E+1,E+cnt+1);
        for(i=1;i<=cnt;i++)
        {
            Edge tmp=E[i];
            int x=tmp.U,y=tmp.V,z=tmp.Quan;
            int xx=GetFa(x),yy=GetFa(y);
            if(xx==yy) continue;
            Father[xx]=yy;
            add(x,y,z);
            add(y,x,z);
        }
        for(i=1;i<=n;i++) Root=i,dfs(i,0,0);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++) if(Path[i][j]!=Dis[i][j])
            {
                puts("NO"); exit(0);
            }
        }
        puts("YES");
    }
}
int main()
{
    int i,j;
    R(n);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++) R(Dis[i][j]);
    }
    for(i=1;i<=n;i++)
    {
        if(Dis[i][i]) return puts("NO"),0;
        for(j=1;j<i;j++) if((Dis[j][i]!=Dis[i][j])||(!Dis[j][i])) return puts("NO"),0;
    }
    Tree::Solve();
    return 0;
}
/*
Input
3
0 2 7
2 0 9
7 9 0
Output
YES

Input
3
1 2 7
2 0 9
7 9 0
Output
NO

Input
3
0 2 2
7 0 9
7 9 0
Output
NO

Input
3
0 1 1
1 0 1
1 1 0
Output
NO

Input
2
0 0
0 0
Output
NO
*/
View Code

 

 
posted @ 2019-04-29 22:25  yccdu  阅读(256)  评论(0编辑  收藏  举报