http://acm.hdu.edu.cn/showproblem.php?pid=3721
题意:一棵树 选择一条边移动边的位置 使移动后任然是一棵树 要求这棵树的直径最小
要移动的边一定在原来树的直径上 找到这条直径 枚举所有的边
每次枚举一条边时 原来的树就变成了两个树 假设两个树的直径 半径分别为
d1,r1 d2,r2 那么重新组成的树的直径应该是 d1,d2,r1+r2+此边长度 中最大的那个
关于一颗树怎么找直径 首先从任意一点出发 找到其他点的距离 最远距离的那个点 一定是直径的其中一个端点 以这个端点为起点再搜一遍就
找到另一个端点了
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<set> #include<queue> #include<map> #include<string> #include <iomanip> using namespace std; const int INF=0x3f3f3f3f; const int N=2505; int head[N],I; struct node { int j,k,next; }side[N*2]; int f[N]; int dist[N]; bool visited[N]; vector<int>po; vector<int>si; int n; void Add(int i,int j,int k) { side[I].j=j; side[I].k=k; side[I].next=head[i]; head[i]=I++; } int bfs(int s,int limit) { queue<int>qt; memset(f,-1,sizeof(f)); memset(dist,0,sizeof(dist)); memset(visited,false,sizeof(visited)); qt.push(s); visited[s]=true; while(!qt.empty()) { int x=qt.front(); qt.pop(); for(int t=head[x];t!=-1;t=side[t].next) { if(visited[side[t].j]||t==limit||t==(limit^1)) continue; visited[side[t].j]=true; f[side[t].j]=(t^1); dist[side[t].j]=dist[x]+side[t].k; qt.push(side[t].j); } } int k=s; for(int i=0;i<n;++i) { if(f[i]!=-1&&dist[i]>dist[k]) k=i; } return k; } int main() { //freopen("data.txt","r",stdin); int T; scanf("%d",&T); for(int ca=1;ca<=T;++ca) { memset(head,-1,sizeof(head)); I=0; scanf("%d",&n); for(int i=1;i<n;++i) { int l,r,k; scanf("%d %d %d",&l,&r,&k); Add(l,r,k); Add(r,l,k); } if(n==1) {printf("Case %d: %d\n",ca,0);continue;} int k=bfs(bfs(0,INF),INF); si.clear(); po.clear(); while(f[k]!=-1) { si.push_back(f[k]); po.push_back(k); k=side[f[k]].j; } int ans=INF; for(int unsigned i=0;i<si.size();++i) { int l=po[i]; int r=side[si[i]].j; int d1,r1=INF; int d2,r2=INF; int k1=bfs(bfs(l,si[i]),si[i]); d1=dist[k1]; int tmp=0; while(f[k1]!=-1) { tmp+=side[f[k1]].k; r1=min(r1,max(tmp,d1-tmp)); k1=side[f[k1]].j; } if(d1==0) r1=0; int k2=bfs(bfs(r,si[i]),si[i]); d2=dist[k2]; tmp=0; while(f[k2]!=-1) { tmp+=side[f[k2]].k; r2=min(r2,max(tmp,d2-tmp)); k2=side[f[k2]].j; } if(d2==0) r2=0; ans=min(ans,max(r1+r2+side[si[i]].k,max(d1,d2))); } printf("Case %d: %d\n",ca,ans); } return 0; }