标签:
题目地址: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