AcWing341 CH6101 最优贸易

题意:

一个有向图,一个物品在每个点有不同的价值,从起点到终点的路径上,可以先在某个点买一个,再在某一个点卖掉,问能赚到最多的钱是多少。

题解:

一开始以为是求路径上最大点权之差,但是发现必须先买才能在卖,顺序不能反。这样一个问题,我们将其分割成两个单调的子问题,从起点到一点的路径上,能用最少多少钱买到物品;从一点到终点,能用最多多少钱卖掉物品。在第一个问题里把物品价值取相反数,在第二个问题里建一个反图,就成了两个相同的问题。遍历每个点,用最多的钱减去最少的钱就是答案。

注意不能反过来。不能说从起点到一点的路径上,能用最多多少钱卖掉物品;从一点到终点,能用最少多少钱买到物品。对于一个点,要保证买东西的点一定在起点到该点之间,卖东西的点一定在该点到终点之间。如果反过来,那就可能导致”先卖再买“的情况。

这样一个图上前缀最大的问题,跟最短路差不多,只是将更新的 d i s [ x ] = d i s [ y ] + w dis[x]=dis[y]+w dis[x]=dis[y]+w换成了 d i s [ x ] = m a x ( d i s [ y ] , p r i c e [ x ] ) dis[x]=max(dis[y],price[x]) dis[x]=max(dis[y],price[x])。所以可以用spfa来解决。但是注意,不能保证一个点只更新一次。因为我们更新的过程不是单调的,由于 p r i c e [ x ] price[x] price[x]的存在,后面的 d i s [ x ] dis[x] dis[x]不一定大于前面 d i s [ y ] dis[y] dis[y]。所以我个人认为不能用Dijstra,但是书上说可以。

经过一些巧妙的设计,可以显著减少代码量。

AC代码:

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--) 
#define lepp(i,a,b) for(int i=(a);i>(b);i--)
#define sci(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define scs(x) scanf("%s",(x))
#define pri(x) printf("%d\n",(x))
#define prl(x) printf("%lld\n",(x))
#define prs(x) printf("%s\n",(x))
#define pii pair<int,int>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back 
#define fi first
#define se second
#define All(x) x.begin(),x.end() 
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define INFF 0x3f3f3f3f3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=1e5+5;
const int mod=1e9+7;
const db eps=1e-6;                                                                            
const db pi=acos(-1.0);
int n,m,p[N],q[N],dis[N],vis[N];
vector<int>tr1[N],tr2[N];
void dij(vector<int>tr[N],int s,int pq[N]){
    priority_queue<pii>d;
    d.push({pq[s],s});
    rep(i,1,n) dis[i]=-INF;
    dis[s]=pq[s];
    while(d.size()){
        pii tmp=d.top();
        d.pop();
        // if(vis[tmp.first]) continue;
        // vis[tmp.first]=1;
        for(auto v:tr[tmp.second]){
            int cur=max(tmp.first,pq[v]);
            if(cur>dis[v]){
                dis[v]=cur;
                d.push({cur,v});
            }
        }
    }
    rep(i,1,n) pq[i]=dis[i];
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    cin>>n>>m;
    rep(i,1,n){
        cin>>q[i];
        p[i]=-q[i];
    }
    rep(i,1,m){
        int u,v,w;
        cin>>u>>v>>w;
        tr1[u].push_back(v);
        tr2[v].push_back(u);
        if(w==2){
            tr1[v].push_back(u);
            tr2[u].push_back(v);
        }
    }
    dij(tr1,1,p);
    dij(tr2,n,q);
    int ans=0;
    rep(i,1,n) ans=max(ans,q[i]+p[i]);
    cout<<ans<<endl;
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/112726082