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

来源:互联网 发布:用友软件电话 编辑:程序博客网 时间:2024/05/24 05:42

题目地址: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 debuusing 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;}



0 0
原创粉丝点击