题意:
有一棵树, 节点表示城市, 每个城市有一个人. 人们要旅行到其他城市. 相当于一个置换. 求总的路程最大值.
思路:
ans = Σ (每条路长 l )*(经过这条路的最大次数 f )
f = 2 * 这条边左边节点数和右边节点数最小值k. (这样左边的每一个点一定能够对应右边的某个点)
这个k可以dfs 求得.
但是直接dfs 会爆栈...
需要将其改为非递归...
#include <stdio.h> #include <cstring> #include <stack> using namespace std; struct gtype { int y,d,next; } g[200010]; int first[100100],tot,a[100100],tt,x,y,d,n; bool v[100100]; inline int min(int a,int b) { if (a<b) return a; else return b; } void add(int x,int y,int d) { tot++; g[tot].d=d; g[tot].y=y; g[tot].next=first[x]; first[x]=tot; tot++; g[tot].d=d; g[tot].y=x; g[tot].next=first[y]; first[y]=tot; } void dfs(int p) { stack <int> stk; int t=first[p]; stk.push(p); v[p]=true; while (1) { if (t==-1)//该点的所有边已经遍历完 { int y = stk.top(); stk.pop(); if (stk.empty()) break;//dfs结束 a[stk.top()]+=a[y]; //该点的子树节点数加到其父节点上, 表示该节点相对其父节点已经处理完 } int x = stk.top();///每次从栈顶取出元素!! t = first[x]; while (t!=-1) { if (!v[g[t].y]) { v[g[t].y]=true; stk.push(g[t].y); break;///一旦前进,便跳出,继续判断或者取栈顶元素.否则就相当于bfs了!!! } t=g[t].next; } } } int main() { scanf("%d",&tt); for (int cas=1; cas<=tt; cas++) { tot=0; memset(g,0,sizeof(g)); memset(first,-1,sizeof(first)); scanf("%d",&n); for (int i=1; i<n; i++) { scanf("%d%d%d",&x,&y,&d); add(x,y,d); } for (int i=1; i<=n; i++) a[i]=1;//记录节点的儿子数,初始化时已经算上了自己 memset(v,0,sizeof(v)); dfs(1);//填a数组 __int64 ans=0; for (int i=1; i<=2*(n-1); i+=2) {//遍历池子,即遍历每一条边 x=g[i].y; y=g[i+1].y; d=min(a[x],a[y]); ans+=min(d,n-d)*2*g[i].d; } printf("Case #%d: %I64d\n",cas,ans); } return 0; }
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int MAXN = 100005; typedef long long ll; struct edge { int v, w, next; }g[MAXN<<1]; int head[MAXN],num; int a[MAXN]; bool vis[MAXN]; int n; stack<int> s; void add(int u, int v, int w) { g[++num].v = v; g[num].w = w; g[num].next = head[u]; head[u] = num; g[++num].v = u; g[num].w = w; g[num].next = head[v]; head[v] = num; } void dfs(int k) { memset(vis,false,sizeof(vis)); vis[k] = true; s.push(k); int t = head[k]; while(true) { if(!t) { int u = s.top(); s.pop();//deal with tmp node if(s.empty()) break; a[s.top()] += a[u]; } int u = s.top(); t = head[u]; while(t) { if(!vis[g[t].v]) { vis[g[t].v] = true; s.push(g[t].v); break; } t = g[t].next; } } } int main() { int T,cas = 0; scanf("%d",&T); while(T--) { num = 0; memset(head,0,sizeof(head)); memset(g,0,sizeof(g)); scanf("%d",&n); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } for(int i=1;i<=n;i++) a[i] = 1; dfs(1); ll ans = 0; for(int i=1;i<2*(n-1);i+=2) { int u = g[i].v; int v = g[i+1].v; int k = min(a[u],a[v]);//a记录子树大小,较小的那个是"一边的节点数" ans += 2ll*min(k,n-k)*g[i].w;//n-k是对面的个数 } printf("Case #%d: %I64d\n",++cas,ans); } }