题目:洛谷P1073、Vijos P1754、codevs1173。
题目大意:有n点m边的图,边分有向和无向。每个点有一个价格,用这个价格可以买入或卖出一个东西。一个人从1出发,要到n,途中可以买入卖出一次(可以不买入卖出),问最多能赚多少钱?
解题思路:首先,要在点i卖出,买入的最低价格为点1到点i的所有路径中,经过的价格最低的一个点的价格。这个用一个BFS扫一遍即可。
然后,有些点是不能到n的(因为有有向边),这些点不能卖出。要求哪些点能到n,只需建反向图,再在反向图里从n开始BFS一遍即可。最后即可得出答案。
C++ Code:
#include<cstdio> #include<vector> #include<queue> #include<cstring> using namespace std; vector<int>G[100005],G2[100005]; int n,m,money[100005],minE[100005]; bool used[100005],ok[100005]; queue<int>q; inline void addedge(int from,int to,int isTwo){ G[from].push_back(to); if(isTwo==2)G[to].push_back(from); } inline void addINVedge(int from,int to,int isTwo){ G2[to].push_back(from); if(isTwo==2)G2[from].push_back(to); } void BFS(int t){ q.push(t); memcpy(minE,money,sizeof minE); memset(used,0,sizeof used); used[t]=1; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(minE[v]>minE[u]){ minE[v]=minE[u]; if(!used[v]){ used[v]=true; q.push(v); } }else if(!used[v]){ used[v]=true; q.push(v); } } } } void BFS2(int t){ q.push(t); memset(ok,0,sizeof ok); ok[t]=true; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<G2[u].size();++i){ int v=G2[u][i]; if(!ok[v]){ ok[v]=true; q.push(v); } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)scanf("%d",money+i); while(m--){ int u,v,two; scanf("%d%d%d",&u,&v,&two); addedge(u,v,two); addINVedge(u,v,two); } BFS(1); BFS2(n); int ans=0; for(int i=1;i<=n;++i) if(ok[i]){ int p=money[i]-minE[i]; if(p>ans)ans=p; } printf("%d ",ans); return 0; }