题目:
http://acm.hdu.edu.cn/showproblem.php?pid=6201
题意:
有n个城市,有n-1条道路将n个城市连接成一个整体,即一个树。一本在每个城市的价格不同,任选一个城市买书,再任选一个城市卖掉书,每条道路都有花费,问最多能赚多少钱
思路:
先说最短路,起点终点都是不确定的,所以建源点和汇点,把所有点连到源点和汇点上去,从源点向所有城市连边,权值为此城市书的价格的取反,意为从此城市买入书,从所有城市向汇点连边,权值为此城市书的价格,意为从此城市卖出书,然后两城市之间连边,权值为路径花费的取反,意为花掉的价格,这样跑最短路,跑出来的答案是最少赚钱数,在之前的基础上把建图的所有边权取反,跑出最短路再取反,就是最大赚钱数了
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*10];
int cnt, head[N];
int val[N];
int dis[N];
bool vis[N];
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
}
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
int spfa(int s, int t)
{
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
queue<int> que;
que.push(s), dis[s] = 0, vis[s] = true;
while(! que.empty())
{
int v = que.front(); que.pop();
vis[v] = false;
for(int i = head[v]; ~i; i = g[i].next)
{
int u = g[i].to;
if(dis[u] > dis[v] + g[i].cost)
{
dis[u] = dis[v] + g[i].cost;
if(! vis[u]) que.push(u), vis[u] = true;
}
}
}
return dis[t];
}
int main()
{
int t, n;
scanf("%d", &t);
while(t--)
{
init();
scanf("%d", &n);
int ss = 0, tt = n + 1;
int a, b, c;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a);
add_edge(ss, i, a); add_edge(i, tt, -a);
}
for(int i = 1; i <= n-1; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c); add_edge(b, a, c);
}
printf("%d\n", -spfa(ss, tt));
}
return 0;
}
树形dp的话,定义dp[i][0]为以i为根的子树中任一点买入书后的身上钱的最大值(显然是负值),dp[i][1]为以i为根的子树中任一点卖出书后的身上钱的最大值,那么在以i为根的子树中实现整个操作所得的最大钱数就是dp[i][0]+dp[i][1],比最短路难懂一些
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, cost, next;
}g[N*2];
int cnt, head[N];
int val[N];
int dp[N][2];
int ans;
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
}
void add_edge(int v, int u, int cost)
{
g[cnt].to = u, g[cnt].cost = cost, g[cnt].next = head[v], head[v] = cnt++;
}
void dfs(int v, int fa)
{
dp[v][0] = -val[v];
dp[v][1] = val[v];
for(int i = head[v]; ~i; i = g[i].next)
{
int u = g[i].to;
if(u == fa) continue;
dfs(u, v);
dp[v][0] = max(dp[v][0], dp[u][0] - g[i].cost);
dp[v][1] = max(dp[v][1], dp[u][1] - g[i].cost);
}
ans = max(ans, dp[v][0] + dp[v][1]);
}
int main()
{
int t, n;
scanf("%d", &t);
while(t--)
{
init();
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
int a, b, c;
for(int i = 1; i <= n-1; i++)
{
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c); add_edge(b, a, c);
}
ans = 0;
dfs(1, 0);
printf("%d\n", ans);
}
return 0;
}