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