hdu6201transaction transaction transaction

来源:互联网 发布:火龙果软件 杨秀峰 编辑:程序博客网 时间:2024/06/05 11:04

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201

题目大意:题目给定一颗具有n个节点的树,每个节点有相对应的权值(为书的价格),且节点i到节点j具有边权值(为从i到j的路费),求任意选定两点,一点买书,一点卖书,能得到的最大利润。

题目思路:对于这道题,我想起了前一次的网络赛的题目,那道题是求从任一点出发能得到的最长路径,思路是加一个源点0,并且对0到1~n建立边,边权为0,这样就转化为求单点的最长路。同理这道题,假设在s点买书,e点卖书,则最终利润为a[e]-a[s]+w[s-e](s到e的路费,这里对边权进行取反操作),则不妨加一个源点0的同时,再加一个汇点n+1,并对0建立边,边权为a[i],对n+1建立边,边权为-a[i],这样就转化为求0->n+1的最长路。

如图所示,0,n+1点必过其中一点。蓝线可为a[i],红线为-a[i],边权取反。

ac代码:
//#include<bits/stdc++.h>//hdu上这玩意打不开
#include<cstdio>
#include<iostream>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
const int N=100005;
const int maxn=0x3f3f3f3f;
int head[2*N],p,a[N],dp[N],n,vis[N];
struct node{
    int f,t,next,w;
    node(int f=0,int t=0,int w=0,int next=0):f(f),t(t),w(w),next(next){}    
}edge[5*N];//这里特坑,明明是re,偏偏显示timelimit,开大点
void add(int f,int t,int w){
    edge[p]=node(f,t,w,head[f]);
    head[f]=p++;
}
queue<int>q;
void spfa(){
    for(int i=0;i<=n+1;i++) dp[i]=0,vis[i]=0;    
    q.push(0);
    while(!q.empty()){
        int s=q.front();
        vis[s]=0;
        q.pop();
        for(int i=head[s];i!=-1;i=edge[i].next){
            int x=edge[i].t,y=edge[i].w,z=edge[i].f;
            if(dp[x]<dp[z]+y){
                dp[x]=dp[z]+y;
                if(!vis[x]){
                    vis[x]=1;
                    q.push(x);
                }    
            }
        }
    }
    printf("%d\n",dp[n+1]);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        p=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        int t1,t2,t3;    
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++){
            scanf("%d %d %d",&t1,&t2,&t3);
            add(t1,t2,-1*t3);
            add(t2,t1,-1*t3);
        }
        for(int i=1;i<=n;i++){
            add(0,i,a[i]);
            add(i,n+1,-1*a[i]);
        }
        spfa();
    }
    return 0;
}


原创粉丝点击