一.题目链接:
最优贸易
二.题目大意:
给一张点权图,从 1 走到 n.
每个点货物的价格为该点点权,最多进行一次买卖.
求最大收益.
三.分析:
这也能用分层图...
由于只进行一次买卖,可以建立三层图 -- 未买未卖、已买未卖、已买已卖.
层内的边权为 0,层之间的边权为点权.
详见代码.
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
const int M = (int)1e5;
const int inf = 0x3f3f3f3f;
int n, m;
int w[M + 5];
int cnt;
int head[M * 3 + 5];
struct node
{
int v, w, nx;
}Edge[M * 50 + 5];
int dis[M * 3 + 5];
bool vis[M * 3 + 5];
void init(int n)
{
cnt = 0;
for(int i = 1; i <= n; ++i)
{
vis[i] = 0;
dis[i] = -inf;
head[i] = -1;
}
}
void add(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].nx = head[u];
head[u] = cnt++;
}
void add_edge(int x, int y)
{
add(x, y, 0);
add(x + n, y + n, 0);
add(x + n * 2, y + n * 2, 0);
add(x, y + n, -w[x]);
add(x + n, y + n * 2, w[x]);
}
struct cmp
{
bool operator()(int a, int b)
{
return dis[a] < dis[b];
}
};
priority_queue <int, vector<int>, cmp> q;
void spfa(int s)
{
q.push(s);
vis[s] = 1, dis[s] = 0;
while(!q.empty())
{
int u = q.top();
q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = Edge[i].nx)
{
int v = Edge[i].v;
if(dis[v] < dis[u] + Edge[i].w)
{
dis[v] = dis[u] + Edge[i].w;
if(!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d %d", &n, &m);
init(n * 3);
for(int i = 1; i <= n; ++i)
scanf("%d", &w[i]);
for(int i = 0, x, y, z; i < m; ++i)
{
scanf("%d %d %d", &x, &y, &z);
add_edge(x, y);
if(z == 2) add_edge(y, x);
}
add(n, 2 * n, 0);
add(2 * n, 3 * n, 0);
spfa(1);
printf("%d\n", dis[n * 3]);
return 0;
}