题意如下:
有一个节点为 n 的树,每个节点有权值,边也有权值,问那两个点 S T 使得 t -s -sum最大
(sum 为从 s 走到 t 上所有边权值之和)
这道题可以转化成最大路径,
源点选择为 0 汇点选择的为 n+1
把每条边的权值设为负数, 起点到每个点的权值也为负数,每个点到终点的权值为正数,
跑一边 最大路径 就是结果了
起点到每个点的边权就是 点权。。。
以下为 AC 代码, 用的 spfa
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int dis[maxn];
int vis[maxn];
int head[maxn],num;
struct node
{
int v,w;
int nxt;
}ed[maxn<<2];
void add(int u,int v,int w)
{
ed[num].v = v;
ed[num].w = w;
ed[num].nxt = head[u];
head[u] = num++;
}
void spfa()
{
queue<int> q;
vis[0] = 1;
dis[0] = 0;
q.push(0);
while(q.size())
{
int u =q.front();
q.pop();
vis[u] = 0;
for(int i=head[u];i!=-1;i=ed[i].nxt)
{
int v = ed[i].v;
int w = ed[i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
void init()
{
num = 0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
memset(dis,-INF,sizeof(dis));
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
int u,v,w;
for(int i=1;i<=n;i++)
{
scanf("%d",&w);
add(0,i,-w);
add(i,n+1,w);
}
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,-w);
add(v,u,-w);
}
spfa();
printf("%d\n",dis[n+1]);
}
return 0;
}