[luogu]P1073:最优贸易

原题链接

最优贸易

分析

先分析题意:
给定一张图,点序号为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 ;
}



原文地址:https://www.cnblogs.com/onglublog/p/9859727.html