【刷题】【bfs】最优贸易
题目地址:P1073 [NOIP2009 提高组] 最优贸易 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目大意:
n个城市,m条道路,道路可能是单向或者双向
同时每个城市有个商品价格,遍历中只能进行一次买卖
从1出发到n结束,求最大获利
数据范围:
输入数据保证 1号城市可以到达n号城市。
对于 10%的数据,1≤n≤6
对于 30%的数据,1≤n≤100
对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。
对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市水晶球价格≤100。
先简单分类:
无环图的情况,可以从1出发,buy[N]记录路径上最低价格
再从n出发,sell[N]记录路径上最高的价格
则如果有边(u,v),ans=max( ans , sell[v]-buy[u] )
有环图,考虑tarjian缩点
然后按照无环图操作
以下为法2: bfs + 贪心
神奇的bfs证联通,然后贪心,求每一种可能路径上的差值,最后求结果
#include<cstdio> #include<cstdlib> #include<queue> #include<algorithm> using namespace std; int n,m; const int N=100003,M=500003; int val[N]; int tot[2],head[2][N]; int ev[2][M<<1],enx[2][M<<1]; void add(int u,int v,int k) { ev[k][++tot[k]]=v,enx[k][tot[k]]=head[k][u],head[k][u]=tot[k]; } bool link[2][N]; void bfs(int k,int st) { queue <int> q; q.push(st),link[k][st]=true; while(!q.empty() ) { int nw=q.front() ;q.pop() ; for(int i=head[k][nw];i;i=enx[k][i]) { int nx=ev[k][i]; if(!link[k][nx] ) link[k][nx]=true,q.push(nx); } } } int d[N],mx[2][N]; bool cmp(int a,int b) { return val[a]<val[b]; } void get_ans(int k,int st,int v) { mx[k][st]=v; queue <int> q; q.push(st); while(!q.empty() ) { int nw=q.front() ;q.pop() ; for(int i=head[k][nw];i;i=enx[k][i]) { int nx=ev[k][i]; if(!mx[k][nx] && link[k^1][nx] ) mx[k][nx]=v,q.push(nx); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++ ) scanf("%d",&val[i]),d[i]=i; while(m--) { int qa,u,v; scanf("%d%d%d",&u,&v,&qa ); add(u,v,0),add(v,u,1); if(qa==2 ) add(v,u,0),add(u,v,1); } bfs(0,1),bfs(1,n); sort(d+1,d+n+1,cmp); for(int i=1;i<=n;i++) if(link[0][d[i]] && link[1][d[i]] && !mx[0][d[i]] ) get_ans(0,d[i],val[d[i]]); for(int i=n;i>0;i--) if(link[0][d[i]] && link[1][d[i]] && !mx[1][d[i]] ) get_ans(1,d[i],val[d[i]]); int ans=0; for(int i=1;i<=n;i++) if(link[0][i] && link[1][i] ) ans=max(ans,mx[1][i]-mx[0][i] ); printf("%d\n",ans); return 0; }