transaction transaction transaction
题意:一个商人得知《the Man Who Changed China》此书很火,决定在一座城市批发一本书(你没有看错,就是一本),带到另一座城市卖,赚取差价,但是由一座城市到另一座城市要花钱打车(打车费用是1元/km);已知共有n座城市,由n-1条路连接,交通网是一棵树;已知此书在每座城市的价格,以及每条路的长度,问买了一本书再卖出后商人最多盈利多少?(商人可以以任意城市为起点);
思路:网上有种二维DP解法硬是没看懂,还是写我的一维加两次dfs解法吧~~
对于每一个节点来说多可能买书卖书,这里我们把u节点看作是在这里卖书,在其他节点买书,也就是说u是终点;问题来了,商人是从u的son节点来的还是u的father节点来的?必是其中一种情况,从son节点来的记为donw,从father节点来的记为up,那么商人最终的盈利为val-min(down, up);
现在的问题是求up和down;
down最好求了,一遍bfs,down[u]=min(val[son]+w, down[son]+w) (w表示u到son的花费)
up就有点绕了;;;
如上图,蓝色路径是down[u], 紫色路径是up[fa], 由图可知,up[fa]+w并不是up[u],而w+红色路径才是up[u],所以说求up与down并不同,因为up[u]的路线可能是经由u的father,再经由father的father,也可能是经由father后,再经由father的son即u的brother;up[u]=min(up[fa], down[fa])??? 如果down[fa]未经由u当然这样了,但上图可知,红色路径并非是down,蓝色路径才是,红色路径只是次短路,,所以还要记录u是否在up[fa]的最短路径上,同时还要求出fa的此短路,现在就明确了:
up[u]=min(val[fa]+w, up[fa]+w, down[fa]+w);注意此式的一个条件u不在down[fa]上,若u在down[fa]上,则将down[fa]改为此短down[fa];
详情请看代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int up[maxn], down[maxn][2];//down[i][0]表示在i的子节点买书到i的最小花费,down[i][1]表示次小花费;
int path[maxn];//path[u]=v表示u到子节点的最短路经由v;
int val[maxn];
struct node{
int v, w, nxt;
node(){};
node(int v0, int w0, int n){
v=v0, w=w0, nxt=n;
}
}edge[maxn<<1];
int head[maxn], cnt;
void add(int u, int v, int w){
edge[cnt]=node(v, w, head[u]);
head[u]=cnt++;
}
void dfs_down(int u, int fa){
down[u][0]=down[u][1]=INF;
for(int i=head[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v, w=edge[i].w;
if(v==fa) continue;
dfs_down(v, u);
int temp1, temp2;//temp1表示最短路,temp2表示此短路;
if(val[v]+w<down[v][0]+w) temp1=val[v]+w, temp2=down[v][0]+w;
else temp1=down[v][0]+w, temp2=min(val[v]+w, down[v][1]+w);
if(temp1<down[u][0]){
down[u][1]=down[u][0];
down[u][0]=temp1;
path[u]=v;
}
else down[u][1]=min(down[u][1], temp1);
}
}
void dfs_up(int u, int fa){
for(int i=head[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v, w=edge[i].w;
if(v==fa) continue;
up[v]=val[u]+w;
if(path[u]==v){
up[v]=min(up[v], min(up[u]+w, down[u][1]+w));
}
else{
up[v]=min(up[v], min(up[u]+w, down[u][0]+w));
}
dfs_up(v, u);
}
}
int main(){
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &val[i]);
}
cnt=0;
memset(head, -1, sizeof(head));
for(int i=1; i<n; i++){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dfs_down(1, 1);
up[1]=INF;//把1看作根节点,所以1没有father,up[1]=INF;
dfs_up(1, 1);
int ans=-INF;
for(int i=1; i<=n; i++){
ans=max(ans, val[i]-min(down[i][0], up[i]));
}
printf("%d\n", ans);
}
return 0;
}