[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\n",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 ;
}


猜你喜欢

转载自www.cnblogs.com/onglublog/p/9859727.html