牛客寒假6-I |最小生成树 + 重新建图 (+ floyd)

题目地址:https://ac.nowcoder.com/acm/contest/3007/I

思路

代码

代码1:最小生成树 + floyd

最小生成树的时候,保存n-1条边即答案。
floyd求点到点的最短距离,复杂度O(N^3)能过

代码2:最小生成树 + dfs求各点到根距离 + 重新建图

最小生成树的时候使用邻接表重新建图。
dfs求各点到根的距离,就能判断是否合法,为什么?因为树上每个点到根的距离是唯一的,所以两点之间距离 = 点1到根 + 点2到根 也是唯一的。

#include<bits/stdc++.h>
using namespace std;

const int maxn= 610;
const int maxm = 1000000;

struct edge{
    int u,v,w;
    bool operator < (const edge &a) const{
        return w < a.w;
    }
}e[maxm];

struct node{
    int v,w;
};

vector<node> g[maxn];

int fa[maxn],n,m,len = 0;

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

int dist[maxn],dis[maxn][maxn];
vector<int> ans;
int a[maxn][maxn];

void init(){
    memset(dis,0x3f3f3f3f,sizeof dis);
    for(int i = 1;i <= n;i++){
        dis[i][i] = 0;
    }
} 

void floyd(){
    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]);
            }
        }
    }
}

int main() {
    cin>> n;
    len = 0;
    init();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) cin>>a[i][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i < j) e[len].u = i,e[len].v = j,e[len].w = a[i][j],len++;
        }
    }
    sort(e,e+len);
    for(int i=1;i<=n;i++) fa[i] = i;
    int sum = 0;
    for(int i=0;i<len;i++){
        int x = get(e[i].u), y = get(e[i].v);
        if(x != y){ //并查集求得最短边长 
            fa[x] = y;
            ans.push_back(e[i].w); //存答案 
            dis[e[i].u][e[i].v] = dis[e[i].v][e[i].u] = e[i].w; //记录新的邻接矩阵 
            sum += e[i].w;
        }
    }
    floyd(); //跑最短路 求出点到点的最短距离 500^3 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(a[i][j] != dis[i][j]){
                cout<<"No"<<endl;
                return 0;
            }
        }
    }
    cout<<"Yes"<<endl; 
    //升序输出边长 
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
    return 0;
}
#include<bits/stdc++.h>
using namespace std;

const int maxn= 610;
const int maxm = 1000000;

struct edge{
    int u,v,w;
    bool operator < (const edge &a) const{
        return w < a.w;
    }
}e[maxm];

struct node{
    int v,w;
};

vector<node> g[maxn];

int fa[maxn],n,m,len = 0;
int vis[maxn];

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

int dist[maxn],dis[maxn][maxn];
vector<int> ans;

void dfs(int x,int fa,int dis){
    dist[x] = dis;
    for(int i=0;i<g[x].size();i++){
        int v = g[x][i].v;
        if(v != fa){
            int w = g[x][i].w;
            dfs(v,x,dis+w);
        }
    }
}

void dfs(int x,int dis){
    dist[x] = dis;
    vis[x] = 1;
    for(int i=0;i<g[x].size();i++){
        int v = g[x][i].v;
        if(!vis[v]){
            int w = g[x][i].w;
            dfs(v,dis+w);
        }
    }
}

int main() {
    cin>> n;
    len = 0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int w;
            cin>>w;
            if(i < j)
                e[len].u = i,e[len].v = j,e[len].w = w,len++;
            dis[i][j] = w;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(dis[i][j] != dis[j][i]){
                puts("No");
                return 0;
            }
        }
    }
    sort(e,e+len);
    for(int i=1;i<=n;i++){
        fa[i] = i;
    }
    int sum = 0;
    for(int i=0;i<len;i++){
        int x = get(e[i].u), y = get(e[i].v);
        if(x != y){
            fa[x] = y;
            ans.push_back(e[i].w); //存储最小生成树的n-1条最短边 
            g[e[i].u].push_back({e[i].v,e[i].w}); //存储新图的邻接表 
            g[e[i].v].push_back({e[i].u,e[i].w}); //存储新图的邻接表 
            sum += e[i].w;
        }
    }
    //找起点(根)
    int s = 1;
    for(int i=1;i<=n;i++){
        if(g[i].size() == 1){
            s = i;
            break;
        }
    } 
    //dfs统计距离 两个版本dfs都可 
    dfs(s,-1,0);  
//  dfs(s,0);
    //与输入的最短距离作比较 
    for(int i=1;i<=n;i++){
        if(dist[i] != dis[s][i]){
            cout<<"No"<<endl;
            return 0;
        }
    }
    cout<<"Yes"<<endl; 
    //升序输出边长 
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fisherss/p/12330410.html