zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    【转】5亿个数找中位数
    C++二维数组名的再探索
    转载 图像卷积
    PowerDesigner的使用一
    Spring注解详解
    JSP页面以及简单的指令
    Javascript学习总结
    html第一天
    Chrome开发,debug的使用方法。
    SVN使用
  • 原文地址:https://www.cnblogs.com/scau20110726/p/3013443.html
Copyright © 2011-2022 走看看