題意:
有一棵樹, 節點表示城市, 每個城市有一個人. 人們要旅行到其他城市. 相當於一個置換. 求總的路程最大值.
思路:
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); }}
/* 自律 專註 保持活力 */