• hdu 6501 transaction transaction transaction 最长路/树形DP/网络流


    最长路:

    设置一个虚拟起点和虚拟终点,每个点与起点间一条负边,值为这个点书的价值的相反数(代表买书花钱),每个点与终点连一条正边,值为这个点的书的价格(代表卖书赚钱)。

    然后按照图中给的边建无向边,权值为负(代表路费)。跑最长路,spfa改一下松弛条件就行

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn = 100000+10;
    const int inf = 1e9;
    int n;
    int cost[100000+10];
    struct node
    {
        int to;
        int w;
        node(int a,int b):to(a),w(b){}
    };
    vector<node>G[maxn];
    int dist[maxn],vis[maxn];
    void spfa()
    {
        queue<int>q;
        for(int i=0;i<=n+1;i++) dist[i] = -inf;
        memset(vis,0,sizeof(vis));
        q.push(0); vis[0] = 1; dist[0] = 0;
        while(!q.empty())
        {
            int u = q.front(); q.pop(); int len = G[u].size();
            for(int i=0;i<len;i++)
            {
                int v = G[u][i].to;
                int w = G[u][i].w;
                if(dist[v]<dist[u]+w)
                {
                    dist[v] = dist[u] + w;
                    if(!vis[v]){vis[v] = 1; q.push(v); }
                }
            }
            vis[u] = 0;
        }
        printf("%d
    ",dist[n+1]);
    }
    int main()
    {
        int cases,u,v,w;
        scanf("%d",&cases);
        while(cases--)
        {
            scanf("%d",&n);
            for(int i=0;i<n+5;i++) G[i].clear();
            for(int i=1;i<=n;i++) scanf("%d",&cost[i]);
            for(int i=1;i<=n;i++)
            {
                G[0].push_back(node(i,-cost[i]));
                G[i].push_back(node(n+1,cost[i]));
            }
            for(int i=1;i<n;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                G[u].push_back(node(v,-w));
                G[v].push_back(node(u,-w));
            }
            spfa();
        }
        return 0;
    }

    树形DP:

    设1为根节点,假设一开始一个人身上的钱为0。

    我们设dp[i][0]表示从根节点走到i及其子树并中任一点买入一本书后这个人身上钱的最大值(显然是负的)。

    dp[i][1]表示从根节点走到i及其子树并中任一点卖出一本书后这个人身上钱的最大值(可正可负)。

    那么我们对这棵树进行一次树形DP即可,dfs后对每个节点更新收益最大值,单点的计算方法为:w=dp[i][0]+dp[i][1]

    (由于前者是负的,相当于收入减去总花费)

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define mst(a,b) memset((a),(b),sizeof(a))
    #define rush() int T;scanf("%d",&T);while(T--)
    
    typedef long long ll;
    const int maxn = 100005;
    const ll mod = 1e9+7;
    const int INF = 0x3f3f3f3f;
    const double eps = 1e-6;
    
    struct node
    {
        int v,w;
        node(int _v,int _w):v(_v),w(_w) {}
    };
    
    int n,ans;
    int val[maxn];
    int dp[maxn][2];
    vector<node>vec[maxn];
    
    void dfs(int u,int pre)
    {
        dp[u][0]=-val[u];
        dp[u][1]=val[u];
        for(int i=0;i<vec[u].size();i++)
        {
            int v=vec[u][i].v;
            int w=vec[u][i].w;
            if(v==pre) continue;
            dfs(v,u);
            dp[u][0]=max(dp[u][0],dp[v][0]-w);
            dp[u][1]=max(dp[u][1],dp[v][1]-w);
        }
        ans=max(ans,dp[u][0]+dp[u][1]);
    }
    
    int main()
    {
        int u,v,w;
        rush()
        {
            scanf("%d",&n);
            for(int i=0;i<=n;i++)
            {
                vec[i].clear();
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&val[i]);
            }
            for(int i=1;i<n;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                vec[u].push_back(node(v,w));
                vec[v].push_back(node(u,w));
            }
            ans=0;
            dfs(1,-1);
            printf("%d
    ",ans);
        }
        return 0;
    }

    网络流:

    直接构图 费用流跑一遍

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<string.h>
    #include<set>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<cmath>
    typedef long long ll;
    typedef unsigned long long LL;
    using namespace std;
    const double PI=acos(-1.0);
    const double eps=0.0000000001;
    const int INF=0x3f3f3f3f;
    const int N=1000000+100;
    int a[N];
    int head[N];
    int dis[N];
    int pre[N];
    int vis[N];
    int tot;
    int m,n;
    struct node{
        int from,to,next,flow,cost;
    }edge[N<<1];
    void init(){
        memset(head,-1,sizeof(head));
        tot=0;
    }
    void add(int u,int v,int c,int cost){
        edge[tot].from=u;
        edge[tot].to=v;
        edge[tot].flow=c;
        edge[tot].cost=cost;
        edge[tot].next=head[u];
        head[u]=tot++;
        edge[tot].from=v;
        edge[tot].to=u;
        edge[tot].flow=0;
        edge[tot].cost=-cost;
        edge[tot].next=head[v];
        head[v]=tot++;
    }
    int spfa(int s,int t){
        memset(pre,-1,sizeof(pre));
        memset(dis,INF,sizeof(dis));
        memset(vis,0,sizeof(vis));
        queue<int>q;
        dis[s]=0;
        vis[s]=1;
        q.push(s);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            vis[x]=0;
            for(int i=head[x];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(edge[i].flow&&dis[v]>dis[x]+edge[i].cost){
                    dis[v]=edge[i].cost+dis[x];
                    pre[v]=i;
                    if(vis[v]==0){
                        vis[v]=1;
                        q.push(v);
                    }
    
                }
            }
        }
        if(pre[t]==-1)return 0;
        return 1;
    }
    int MCMF(int s,int t){
        int flow=0;
        int cost=0;
        while(spfa(s,t)){
            int minn=INF;
            for(int i=pre[t];i!=-1;i=pre[edge[i].from]){
                minn=min(minn,edge[i].flow);
            }
            for(int i=pre[t];i!=-1;i=pre[edge[i].from]){
                edge[i].flow=edge[i].flow-minn;
                edge[i^1].flow=edge[i^1].flow+minn;
                cost=edge[i].cost+cost;
               // cout<<cost<<endl;
            }
            flow=flow+minn;
        }
        return cost;
    }
    int main(){
        int tt;
        scanf("%d",&tt);
        while(tt--){
            init();
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            int s=0;
            int s1=n+1;
            int t=n+2;
            add(s,s1,1,0);
            for(int i=1;i<=n;i++){
                add(s1,i,1,-a[i]);
            }
            for(int i=1;i<=n;i++){
                add(i,t,1,a[i]);
            }
            for(int i=1;i<=n-1;i++){
                int u,v,cost;
                scanf("%d%d%d",&u,&v,&cost);
                add(u,v,1,cost);
                add(v,u,1,cost);
            }
            cout<<abs(MCMF(s,t))<<endl;
        }
    }
  • 相关阅读:
    HTML th nowrap 属性
    C 语言实例 – 判断闰年
    Java MySQL 连接
    Linux shapecfg命令
    C 简介
    Java 之 HashSet 集合
    Java 之 Set 接口
    Java 之 LinkedList 集合
    Java 之 List 接口
    JavaScript 之 事件(详解)
  • 原文地址:https://www.cnblogs.com/Aragaki/p/7520420.html
Copyright © 2020-2023  润新知