码迷,mamicode.com
首页 > 其他好文 > 详细

UVAlive 6622 Absurdistan Roads(最小生成树+LCA)

时间:2016-08-20 19:31:31      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4633

思路:每个点之间连边,权值为两点之间的最短距离。则该图的最小生成树的n-1条边在最终的n条边内。则两点(i,j)之间距离为dist[i]+dist[j]-2*dist[ LCA(i,j) ](dist[i]表示根节点(设为1)到i节点的距离)。若树上每点之间的距离都不大于每点之间的最短距离,则只需任意添加一条边即可。否则,选择不符合条件但权值最小的边,添加(题目保证有解,不符合条件的两点需要走树上的边和该条边,则该条边权值越小越能保证满足条件)。

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debu
using namespace std;
const int maxn=4050;
const int INF=0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w) {}
};
struct Node
{
    int p,w;
    Node(int p=0,int w=0):p(p),w(w) {}
};
int n,cas=0;
queue<int> q;
vector<Edge> e;
int dist[maxn];
vector<Edge> ans;
int anc[maxn][50];
int v[maxn],V[maxn];
int mat[maxn][maxn];
int tree[maxn][maxn];
int fa[maxn],d[maxn];
vector<Node> g[maxn];
int cmp(Edge a,Edge b)
{
    return a.w<b.w;
}
int Find(int x)
{
    return fa[x]==x?x:fa[x]=Find(fa[x]);
}
void init()
{
    e.clear();
    ans.clear();
    memset(v,0,sizeof(v));
    memset(d,0,sizeof(d));
    memset(V,0,sizeof(V));
    memset(anc,0,sizeof(anc));
    memset(tree,0,sizeof(tree));
    for(int i=1; i<=n; i++)
    {
        fa[i]=i;
        g[i].clear();
    }
}
void build()
{
    int tot=0;
    sort(e.begin(),e.end(),cmp);
    //cout<<"*************"<<endl;
    for(int i=0; i<e.size(); i++)
    {
        int x=e[i].u,y=e[i].v,w=e[i].w;
        //cout<<x<<" "<<y<<" "<<w<<endl;
        int xx=Find(x),yy=Find(y);
        if(xx!=yy)
        {
            fa[xx]=yy;
            g[x].push_back(Node(y,w));
            g[y].push_back(Node(x,w));
            ans.push_back(Edge(x,y,w));
            //cout<<x<<" "<<y<<" "<<w<<endl;
            tree[x][y]=tree[y][x]=1;
            //cout<<x<<" "<<y<<" "<<w<<endl;
            if(++tot==n-1) break;
        }
    }
}
void dfs(int x,int dep)
{
    v[x]=1,d[x]=dep;
    for(int i=0; i<g[x].size(); i++)
    {
        int nt=g[x][i].p;
        if(!v[nt])
        {
            anc[nt][0]=x;
            int k=0;
            while(anc[anc[nt][k]][k]!=0)
            {
                anc[nt][k+1]=anc[anc[nt][k]][k];
                k++;
            }
            dfs(nt,dep+1);
        }
    }
}
int LCA(int x,int y)
{
    if(d[x]<d[y]) swap(x,y);
    int l=d[x]-d[y];
    int k=0,ans=INF;
    while(l!=0)
    {
        if(l&1)
        {
            x=anc[x][k];
        }
        l>>=1;
        k++;
    }
    k=0;
    while(x!=y)
    {
        if((anc[x][k]!=anc[y][k])||(!k))
        {
            x=anc[x][k],y=anc[y][k];
            k++;
        }
        else k--;
    }
    return x;
}
void bfs()
{
    memset(V,0,sizeof(V));
    while(!q.empty()) q.pop();
    for(int i=1; i<=n; i++) dist[i]=INF;
    V[1]=1,q.push(1),dist[1]=0;
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=0; i<g[now].size(); i++)
        {
            int nt=g[now][i].p;
            if(V[nt]) continue;
            dist[nt]=min(dist[nt],dist[now]+g[now][i].w);
            V[nt]=1,q.push(nt);
        }
    }
}
void solve()
{
    for(int i=1; i<=n; i++)
        if(!v[i]) dfs(i,0);
    int flag=0,mind=INF,u,v;
    for(int i=1; i<=n; i++)
        for(int j=i+1; j<=n; j++)
        {
            //cout<<i<<" "<<j<<" "<<LCA(i,j)<<endl;
            int mindist=dist[i]+dist[j]-2*dist[LCA(i,j)];
            if(mindist>mat[i][j])
            {
                flag=1;
                if(mat[i][j]<mind)
                {
                    mind=mat[i][j];
                    u=i,v=j;
                }
            }
        }
    if(!flag)
    {
        ans.push_back(Edge(1,2,mat[1][2]));
    }
    else
    {
        ans.push_back(Edge(u,v,mind));
    }
}
int main()
{
#ifdef debug
    freopen("in.in","r",stdin);
#endif // debug
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&mat[i][j]);
                if(i!=j) e.push_back(Edge(i,j,mat[i][j]));
            }
        build();
        bfs();
        solve();
        cas++;
        if(cas!=1) printf("\n");
        for(int i=0; i<ans.size(); i++)
            printf("%d %d %d\n",ans[i].u,ans[i].v,ans[i].w);
    }
    return 0;
}



UVAlive 6622 Absurdistan Roads(最小生成树+LCA)

标签:

原文地址:http://blog.csdn.net/wang2147483647/article/details/52263025

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!