ural(Timus) 1463. Happiness to People!

树DP

题意:输入n和m,表示n个城市,m条无向边,下面一行n个数字,表示每个城市的权值,下面m行是每条边的信息,u,v,w,顶点和边权。问你从一个城市出发,走出一条路线,使得权值和最大,权值和包括这条路线上城市的权值和边的权值和。

题中有一句话出卖了它是个树DP:It turned out that if Petrovich can fly (using one or several flights) from town i to town j, then there is exactly one way to do this.

从一个顶点去另一个顶点如果连通的话只有一条路径,说明这个无向图其实是个无根树,所以又变成了经典问题,在无根树中找两点使它们的路径最长,不过这里要加上点的权值而已,是一样的,另外一个点是要记录路径的,输出路径中经过了多少个点,并且沿路径输出每一个点,如果有多条路径任意一条即可

 

DP思路不说了,可以找前面的题解里面有详细的讲解,说说输出路径。我是分两部分来输出路径的,根到叶子的最大值为一个部分,到叶子的次大值是另一个部分,根据路径输出的要求,前面部分要递归输出,或者可以用一个栈保存,比较懒就用了stl的stack来保存路径,后面的部分不用递归,直接迭代下去,但是为了统计点的个数所以先保存,用了stl的queue来保存路径

整个题目其实不难,注意细节即可

#include <cstdio>

#include <cstring>

#include <utility>

#include <vector>

#include <stack>

#include <queue>

#include <algorithm>

using namespace std;

#define N 50010



typedef long long ll;

typedef pair<ll,ll> pll;

bool vis[N];

vector<pll>a[N];

stack<int>s;

queue<int>q;

ll val[N];

ll dp[N][2];

ll ans;

int n,m,root;

int p[N][2];



void input()

{

    for(int i=0; i<=n; i++) 

        a[i].clear();

    for(int i=1; i<=n; i++) 

        scanf("%lld",&val[i]);

    for(int i=0; i<m; i++)

    {

        int u,v,w;

        pll tmp;

        scanf("%d%d%d",&u,&v,&w);

        tmp.first=v; tmp.second=w; a[u].push_back(tmp);

        tmp.first=u; tmp.second=w; a[v].push_back(tmp);

    }

}



void dfs(int rt)

{

    vis[rt]=true;

    dp[rt][1]=dp[rt][0]=0; 

    p[rt][1]=p[rt][0]=-1;



    int size=a[rt].size();

    for(int i=0; i<size; i++)

    {

        pll tmp = a[rt][i];

        int v = tmp.first;

        int w = tmp.second;

        if(!vis[v])

        {

            dfs(v);

            if(dp[v][1] + w >= dp[rt][1])

            {

                dp[rt][0] = dp[rt][1];

                p[rt][0] = p[rt][1];

                dp[rt][1] = dp[v][1]+w;

                p[rt][1] = v;

            }

            else if(dp[v][1] + w > dp[rt][0])

            {

                dp[rt][0] = dp[v][1] + w;

                p[rt][0] = v;

            }

        }

    }



    dp[rt][1] += val[rt];

    dp[rt][0] += val[rt];

    if( dp[rt][1]+dp[rt][0]-val[rt] > ans)

    {

        root=rt;

        ans = dp[rt][1]+dp[rt][0]-val[rt];

    }

}



int Path1(int rt)

{

    int cc=1;

    int u;

    while(!s.empty()) s.pop();

    s.push(rt);

    for(u=p[rt][1]; u!=-1; u=p[u][1])

    {

        s.push(u);

        cc++;

    }

    return cc;

}



int Path2(int rt)

{

    int cc=0;

    int u;

    while(!q.empty()) q.pop();

    for(u=p[rt][0]; u!=-1; u=p[u][1])

    {

        q.push(u);

        cc++;

    }

    return cc;

}



void solve()

{

    memset(vis,false,sizeof(vis));

    memset(p,-1,sizeof(p));

    ans=-1;   

    /*

    初始化为

    ans=0;

    root=1; //不要初始化为0

    */

    for(int i=1; i<=n; i++)

        if(!vis[i])

            dfs(i);

    printf("%lld\n",ans);



    int c1=Path1(root);

    int c2=Path2(root);

    printf("%d\n",c1+c2);



    while(!s.empty())

    {

        int t=s.top();

        s.pop();

        if(t!=root) printf("%d ",t);

        else        printf("%d",t);

    }

    while(!q.empty())

    {

        int t=q.front();

        q.pop();

        printf(" %d",t);

    }

    printf("\n");

}



int main()

{

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        input();

        solve();

    }

    return 0;

}

 

你可能感兴趣的:(APP)