[HDU 4118]Holiday's Accommodation[图论][非递归dfs]

来源:互联网 发布:广州谷得知乎 编辑:程序博客网 时间:2024/06/06 17:03

题意:

有一棵树, 节点表示城市, 每个城市有一个人. 人们要旅行到其他城市. 相当于一个置换. 求总的路程最大值.

思路:

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);    }}

/* 自律 专注 保持活力 */

原创粉丝点击