出处: NOIp2009提高组T3
主要算法:最短路(SPFA)
难度:4.3
题目要看清楚,旅行商是来旅游的,所以必须保证要从1走到n。
在旅行的过程中要赚的最多的钱。那么我们考虑怎么样才能使赚到的钱最多?成本尽量压低,价格尽量抬高,赚的钱最多。于是我们一定是要从起点开始找出最低的价格,并且找出最高的价格。选择从低的那里买,高的那里卖。
那我们是不是从起点开始做SPFA,同时在每个点更新目前到达的最大值和最小值,最后相减求得最大值就行了?
不对。我们忘记考虑了一个先后的顺序。按照刚才的求法,如果我先走到了最大值的点,再走到最小值的点,那我卖出去赚到的不是负数了吗?既然我们不可能在同一个点买进卖出,那么我们卖出的点一定是在我们到最小值的点之后的。那么如何求得到一个点之后到终点为止所能达到的最大值?那么很显然,我们只需要反向建边做最大值就可以了。
这么说来,我们可以总结一下反向建边的用途。当有向图需要考虑从一个点到另一个固定点之间说经过的一些情况是,正着做就很麻烦,而从终点反着过来就又与我们从起点开始的情况相同了。所以以后碰到这种情况,反向建边总是很有用的。
SPFA做的是边权,而这里是点权。要注意转换。
Code
/*By QiXingzhi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int N = 100010; const int INF = 715827882; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w; } bool inQ[N]; int n,m,ans,x,y,z; int a[N],maxx[N],minx[N]; vector <int> G[N]; vector <int> G2[N]; queue <int> q; inline void AddEdge(int u, int v){ G[u].push_back(v); G2[v].push_back(u); } inline void SPFA1(int s){ memset(minx,0x3f,sizeof(minx)); minx[s] = a[s]; q.push(s); inQ[s] = 1; int cur,to,sz; while(!q.empty()){ cur = q.front(); q.pop(); inQ[cur] = 0; sz = G[cur].size(); for(int i = 0; i < sz; ++i){ to = G[cur][i]; if(minx[cur] < minx[to]){ minx[to] = Min(minx[cur], a[to]); if(!inQ[to]){ q.push(to); inQ[to] = 1; } } } } } inline void SPFA2(int s){ memset(inQ,0,sizeof(inQ)); while(!q.empty()) q.pop(); maxx[s] = a[s]; q.push(s); inQ[s] = 1; int cur,to,sz; while(!q.empty()){ cur = q.front(); q.pop(); inQ[cur] = 0; sz = G2[cur].size(); for(int i = 0; i < sz; ++i){ to = G2[cur][i]; if(maxx[cur] > maxx[to]){ maxx[to] = Max(maxx[cur],a[to]); if(!inQ[to]){ q.push(to); inQ[to] = 1; } } } } } int main(){ //freopen(".in","r",stdin); n = r, m = r; for(int i = 1; i <= n; ++i) a[i] = r; for(int i = 1; i <= m; ++i){ x = r, y = r, z = r; AddEdge(x,y); if(z == 2){ AddEdge(y,x); } } SPFA1(1); SPFA2(n); for(int i = 1; i <= n; ++i){ ans = Max(ans, maxx[i]-minx[i]); } printf("%d",ans); return 0; }
原文:https://www.cnblogs.com/qixingzhi/p/9279635.html