原题链接
分析
先分析题意:
给定一张图,点序号为1-n,你从1点开始旅游,到n点结束旅途。每个点都有卖水晶球(雾),你可以在旅途中买水晶球并在另一个地方卖出,该操作最多进行一次,求最大收益。
暴搜+剪枝+玄学dp
考虑暴搜,暴力搜索每一种走法(可往返),但是这样子程序肯定停不下来,因为可以重复走,需要加入边界使程序停下来。
类似于SPFA的思想,对每个dp状态以及路径最小值进行松弛(差不多理解下)。
- 如果松弛成功的话,不回跳。
- 如果松弛失败,跳出dfs。
dp方程:f[i]表示以i点为终点最大收益。
f[i]=max(f[fa],val[i]-minn)
其中fa为i的父节点,val[i]为i点出售的水晶球价格,minn为路径最小价格。
当结束dfs时,f[n]即为答案。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100009,M=500009;
int read(){
char c;int num;
while(c=getchar(),!isdigit(c));num=c-'0';
while(c=getchar(), isdigit(c)) num=num*10+c-'0';
return num;
}
int n,m,val[N],dp[N],kk[N];
int head[N],nxt[M*2],ver[M],tot=1;
void dfs(int x,int minn,int fa);
int main()
{
int x,y,f;
n=read();m=read();
memset(kk,0x3f,sizeof(kk));
for(int i=1;i<=n;i++)
val[i]=read();
for(int i=1;i<=m;i++){
x=read();y=read();f=read();
ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;
if(f==2){
ver[++tot]=x;nxt[tot]=head[y];head[y]=tot;
}
}
dfs(1,1<<31-1,0);
printf("%d
",dp[n]);
return 0;
}
void dfs(int x,int minn,int fa){
bool f=1;
minn=min(val[x],minn);
if(kk[x]>minn){
kk[x]=minn;
f=0;
}
int maxn=max(dp[fa],val[x]-minn);
if(dp[x]<maxn){
dp[x]=maxn;
f=0;
}
if(f)return ;
for(int i=head[x];i;i=nxt[i])
dfs(ver[i],minn,x);
return ;
}