开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
题意:给出n个点和n个点的出售价格,m条边,可能是单向边也可能是双向边,可以从u点买到东西再到v点卖出,这个活动只能做一次,问可以转的最多的钱是多少 思路:一开始先用vector把图存起来,然后从1号点开始dfs,dfs的参数有(int x,int minn,int pre),分别表示当前的点,到现在为止的最小值,上一个点;函数里需要做的事情就是把最小值更新,即minn=min(c[x],minn),还有更新答案,即f[x]=max(f[pre],c[x]-minn),这个就和动态规划差不多的思想,为了程序不发生mle,需要剪一下枝,如果最小值没更新而且答案也没有更新的话就直接返回就行,因为这个点以前已经被更新过了,而且这一次也没有再更新,说明再往后的点还是和以前一样,所以直接退出就行,类似于vis数组的思想 代码:
#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e18;
const double pi=acos(-1);
const int N=1e6+100;
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
int pri[100005],isp[100005],cnt;
void ispri(int n){
memset(isp,1,sizeof(isp));
isp[0]=isp[1]=0;
for(int i=2;i<=n;i++){
if(isp[i]) pri[++cnt]=i;
for(int j=1;j<=cnt&&pri[j]*i<=n;j++){
isp[pri[j]*i]=0;
if(i%pri[j]==0) break;
}
}
}
int n,m,c[100005],mi[1000005],f[100005];
vector<int>g[100005];
void dfs(int x,int minn,int p){
int flag=1;
minn=min(c[x],minn);
if(mi[x]>minn) mi[x]=minn,flag=0;
int maxx=max(f[p],c[x]-minn);
if(f[x]<maxx) f[x]=maxx,flag=0;
if(flag) return;
for(auto u:g[x]) dfs(u,minn,x);
}
signed main()
{
//ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>c[i],mi[i]=inf;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
g[u].push_back(v);
if(w==2) g[v].push_back(u);
}
dfs(1,inf,0);
cout<<f[n]<<endl;
return 0;
}