!-- Loading 底层遮罩 -->

CF472D Design Tutorial: Inverse the Problem

感谢所有AC

传送门

思路

    先根据所给的邻接矩阵建图。题目要验证是否能形成一棵树,首先这棵树一定是这个图的一个生成树,其次,树中是不存在环的,所以生成树中不能带环。假如有三个点形成了一个环,边权分别为 x,y,z ,同时有 x <= y < z ,那么可以怎么验证树的存在性呢?只要 x+y=z 等式成立,这个树就能构成,当然,这是对于三个点构成的树而言。对于包含n个点的数,只要验证任意三个点的可行性就行。

    考虑怎么代码实现,先把 x 和 y 这两条边加入生成树中,然后对 z 对应的两个点求距离,看看他们在树上的距离是否等于 z ,如果等,则树成立。这个过程少不了对 x,y,z 先进行排序,然后取最短边,取次短边来建树。从这可以发现这个过程分明是求最小生成树的步骤。于是对原图求最小生成树,求树上距离来验证树的存在性。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 2007
using namespace std;
int n, d[maxn][maxn], hd[maxn], dis[maxn], fa[maxn], cnt, m;
struct node {
    int u, v, w;
    bool operator<(const node& a)const {
        return w < a.w;
    }
}edge[maxn*maxn];
struct edgenode {
    int to, val, nxt;
}g[maxn*maxn*2];
int find(int x)
{
    if (x != fa[x])
        return fa[x] = find(fa[x]);
    return x;
}
void add(int u, int v, int w)
{
    g[++cnt].val = w;
    g[cnt].to = v;
    g[cnt].nxt = hd[u];
    hd[u] = cnt;
}
void dfs(int r, int u)
{
    for (int i = hd[u]; i; i = g[i].nxt)
    {
        int v = g[i].to, w = g[i].val;
        if (v == r) continue;
        dis[v] = dis[u] + w;
        dfs(u, v);
    }
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            cin >> d[i][j];
            if (i == j && d[i][j] != 0) { cout << "NO"; return 0; }
            if (i != j && d[i][j] <= 0) { cout << "NO"; return 0; }
            if (i < j)
                edge[++m].u = i, edge[m].v = j, edge[m].w = d[i][j];
        }
    sort(edge + 1, edge + m + 1);
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 1; i <= m; i++)
    {
        int fu = find(edge[i].u), fv = find(edge[i].v);
        if (fu == fv) continue;
        fa[fu] = fv;
        add(edge[i].u, edge[i].v, edge[i].w);
        add(edge[i].v, edge[i].u, edge[i].w);
    }
    for (int i = 1; i <= n; i++)
    {
        dis[i] = 0;
        dfs(0, i);
        for(int j=1;j<=n;j++)
            if (dis[j] != d[i][j])
            {
                cout << "NO";
                return 0;
            }
    }
    cout << "YES";
    return 0;
}
posted @ 2022-05-24 23:59  Thinker-X  阅读(35)  评论(0编辑  收藏  举报