题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6201
思路:
1.选择两点,一点作为买入,一点作为卖出,每经过一条边需一定花费,求最大利润。
2.选择最短路中若求一起点集合到一终点集合的最短路,可通过设置一源点与一汇点求得。
3.对于此问题,可分为买入集合与卖出集合。设置一源点,向所有节点连边,权值为-w[i],在该点买入;设置一汇点,所有节点向其连边,权值为w[i],代表在该点卖出。所有边权值设为-val,代表走此路径花费。求从源点到汇点的最长路经即可(类似最小费用最大流,流量为一时的费用流)。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define S 0
#define T n+1
#define debug
using namespace std;
typedef long long LL;
const int maxn=100000+50;
const int INF=0x3f3f3f3f;
struct Edge
{
int to,nt;
LL w;
};
int n,tot;
queue<int> q;
int vis[maxn];
LL dist[maxn];
int head[maxn];
Edge edge[maxn*4];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,LL w)
{
edge[tot].to=v,edge[tot].nt=head[u];
edge[tot].w=w,head[u]=tot++;
}
void maxdist(int s)
{
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
for(int i=0;i<=n+1;i++) dist[i]=-INF;
q.push(s),vis[s]=1,dist[s]=0;
while(!q.empty())
{
int now=q.front();
q.pop(),vis[now]=0;
for(int i=head[now]; ~i; i=edge[i].nt)
{
int nt=edge[i].to;
LL w=edge[i].w;
if(dist[nt]<dist[now]+w)
{
dist[nt]=dist[now]+w;
if(!vis[nt])
{
vis[nt]=1;
q.push(nt);
}
}
}
}
}
int main()
{
#ifdef debu
freopen("in.txt","r",stdin);
#endif // debug
int t;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
LL x;
scanf("%lld",&x);
addEdge(S,i,-x);
addEdge(i,T,x);
}
for(int i=0; i<n-1; i++)
{
int x,y;
LL w;
scanf("%d%d%lld",&x,&y,&w);
addEdge(x,y,-w);
addEdge(y,x,-w);
}
maxdist(S);
printf("%lld\n",dist[T]);
}
return 0;
}