cf Inverse the Problem (最小生成树+DFS)

题意:

N个点。N行N列d[i][j]。

d[i][j]:结点i到结点j的距离。

问这N个点是否可能是一棵树。是输出YES,否则输出NO。

思路:

假设这个完全图是由一棵树得来的,则我们对这个完全图求最小生成树,得到原树。(画个图就明白)

故我们对完全图求最小生成树,然后用DFS从这棵树上的每个点出发,判断距离是否和矩阵d相同。

注意:

用vector存与每个点相连树枝的另一端,否则超时。用了vector也耗了1400多秒,限时2s。

代码:

#include <cstdio>
#include <iostream>
#include <string.h>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
using namespace std;
int const uu[4] = {1,-1,0,0};
int const vv[4] = {0,0,1,-1};
typedef long long ll;
int const maxn = 50005;
int const inf = 0x3f3f3f3f;
ll const INF = 0x7fffffffffffffffll;
double eps = 1e-10;
double pi = acos(-1.0);
#define rep(i,s,n) for(int i=(s);i<=(n);++i)
#define rep2(i,s,n) for(int i=(s);i>=(n);--i)
#define mem(v,n) memset(v,(n),sizeof(v))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
struct node{
    int x,y,len;
};
int n;
int d[2005][2005], a[2005][2005];
int fa[2005];
node edge[4000005];
vector<int> graph[2005];

bool cmp(node a,node b){
    return a.len<b.len;
}

int findFa(int x){
    if(fa[x]!=x) fa[x]=findFa(fa[x]);
    return fa[x];
}

bool dfs(int start,int x,int fa,int weight){
    if(d[start][x]!=weight){
        return false;
    }
    int L=graph[x].size();
    rep(i,0,L-1){
        int v=graph[x][i];
        if(v==fa) continue;
        bool t=dfs(start,v,x,weight+a[x][v]);
        if(!t) return false;
    }
    return true;
}

int main(){
    scanf("%d",&n);
    rep(i,1,n) rep(j,1,n) scanf("%d",&d[i][j]);

    rep(i,1,n) if(d[i][i]!=0){
        printf("NO\n");
        return 0;
    }
    rep(i,1,n-1) rep(j,i+1,n){
        if(d[i][j]==0 || (d[i][j]!=d[j][i])){
            printf("NO\n");
            return 0;
        }
    }

    int eNum=0;
    mem(a,0);

    rep(i,1,n-1) rep(j,i+1,n){
        edge[++eNum].x=i, edge[eNum].y=j;
        edge[eNum].len=d[i][j];
    }
    sort(edge+1,edge+1+eNum,cmp);
    rep(i,1,n) fa[i]=i;
    rep(i,1,n) graph[i].clear();

    rep(i,1,eNum){
        int xx=edge[i].x, yy=edge[i].y;
        int fx=findFa(xx), fy=findFa(yy);
        if(fx!=fy){
            fa[fx]=fy;
            a[xx][yy]=a[yy][xx]=edge[i].len;
            graph[xx].push_back(yy);
            graph[yy].push_back(xx);
        }
    }

    int t=findFa(1);
    rep(i,2,n) if(findFa(i)!=t){
        printf("NO\n");
        return 0;
    }

    rep(i,1,n){
        bool k=dfs(i,i,-1,0); //从顶点i出发
        if(!k){
            printf("NO\n");
            return 0;
        }
    }
    printf("YES\n");
}
时间: 2024-10-06 03:04:27

cf Inverse the Problem (最小生成树+DFS)的相关文章

Codeforces Round #270 D Design Tutorial: Inverse the Problem --MST + DFS

题意:给出一个距离矩阵,问是不是一颗正确的带权树. 解法:先按找距离矩阵建一颗最小生成树,因为给出的距离都是最短的点间距离,然后再对每个点跑dfs得出应该的dis[][],再对比dis和原来的mp是否一致即可. 首先还要判断一些东西.具体看代码吧. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #in

HDU4081Qin Shi Huang&#39;s National Road System(最小生成树+DFS)

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4227    Accepted Submission(s): 1465 Problem Description During the Warring States Period of ancient China(4

Codeforces Round #270 D. Design Tutorial: Inverse the Problem

D. Design Tutorial: Inverse the Problem 与u最近的边肯定是与u直接相连的边,所以可以根据这个建树,然后就可以求树上两点之间的距离,判断是否全部匹配. 1 #define bug(x) cout<<#x<<" is "<<x<<endl; 2 #define IO std::ios::sync_with_stdio(0); 3 #include <bits/stdc++.h> 4 #def

HDU 1016 Prime Ring Problem --- 经典DFS

思路:第一个数填1,以后每个数判断该数和前一个数想加是否为素数,是则填,然后标记,近一步递归求解. 然后记得回溯,继续判断下一个和前一个数之和为素数的数. /* HDU 1016 Prime Ring Problem --- 经典DFS */ #include <cstdio> #include <cstring> int n; bool primer[45], visit[25]; //primer打素数表,visit标记是否访问 int a[25]; //数组a存储放置的数 /

hdu 1016 Prime Ring Problem (简单DFS)

Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 25700    Accepted Submission(s): 11453 Problem Description A ring is compose of n circles as shown in diagram. Put natural numb

hdu 1016 Prime Ring Problem (dfs)

一切见注释. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; bool vis[22]; int n; int ans[22]; int top; bool isprime(int x)//判断素数 { for(int i=2;i<x;i++) if(x%i==0)return false; return

hdoj 1016 Prime Ring Problem 【DFS】

策略如题 链接 http://acm.hdu.edu.cn/showproblem.php?pid=1016 代码: #include<stdio.h> #include<string.h> int prime[25] = {1, 1}, n, vis[25]; //vis作用:标记是否用过 int a[25]; void f() //找出来前20的素数 判定为0 { for(int i = 2; i <= 24; i ++){ if(prime[i] == 0) for(i

【CF】270D Design Tutorial: Inverse the Problem

题意异常的简单.就是给定一个邻接矩阵,让你判定是否为树.算法1:O(n^3).思路就是找到树边,原理是LCA.判断树边的数目是否为n-1.39-th个数据T了,自己测试2000跑到4s.算法2:O(n^2).思考由图如何得到树,显然MST是可行的.因此,题目变为直接找到MST.然后通过树边构建目标矩阵.判定矩阵是否相等. 1 /* 472D */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #

hdu 5323 Solve this interesting problem(dfs)

题目链接:hdu 5323 Solve this interesting problem 逆向思维,每次向左或向右翻倍,知道左端点为0时,即恰好满足的情况,处理处所有情况去取最小值. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll inf = 0x3f3f3f3f; ll L, R, N; void