codevs1173最优贸易
相当坑爹
原本看完题解还是满怀信心的
结果写了四遍都没过
什么叫两遍spfa就行啊!!!
最后没办法看了人家的代码
自己再想想才写出来
太耻辱了
它其实是先开两个数组
一个是maxn[],一个是minn[]
用于存到到达当前节点的最大卖出值和最小买入值
当然初始化为最小值和最大值就行
这就需要建立反向边
然后每次用类似宽搜的办法扩张出去
正向的搜minn[]
反向的搜maxn[]
先讲正向吧(反向的思路自己根据这个YY)
1.先把第一个节点更新为它自己原来的值,存入队列,标记于队列中
2.出队,标记掉,寻找这个点的出边
3.如果这个点(u点)出边的点(v点)的minn值(minn[v])大于自己的值或者是大于minn[u],就更新它,入队,并标记
如此反复即可
#include <cstdio> #include <iostream> #include <cstring> #include <queue> using namespace std; const int _maxn=100010; queue<int> q; struct e { int to,Next; }a[1000011]; bool vis[_maxn]; int head[_maxn],maxn[_maxn],minn[_maxn],headf[_maxn],a1[_maxn],n,m,k=0; void add(int x,int y) { a[++k].to=y; a[k].Next=head[x]; head[x]=k; a[++k].to=x; a[k].Next=headf[y]; headf[y]=k; } void read() { int x,y,z,ai; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a1[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y); if(z==2) add(y,x); } } void spfa1() { int u,v; memset(vis,false,sizeof(vis)); memset(minn,0x7f,sizeof(minn)); q.push(1); vis[1]=true; minn[1]=a1[1]; while(!q.empty()) { u=q.front(); vis[u]=false; q.pop(); for(int i=head[u];i!=-1;i=a[i].Next) { v=a[i].to; if(minn[v]>min(a1[v],minn[u])) { minn[v]=min(a1[v],minn[u]); if(!vis[v]) { q.push(v); vis[v]=true; } } } } } void spfa2() { int u,v; memset(maxn,0,sizeof(maxn)); memset(vis,false,sizeof(vis)); q.push(n); vis[n]=true; maxn[n]=a1[n]; while(!q.empty()) { u=q.front(); vis[u]=false; q.pop(); for(int i=headf[u];i!=-1;i=a[i].Next) { v=a[i].to; if(maxn[v]<max(a1[v],maxn[u])) { maxn[v]=max(a1[v],maxn[u]); if(!vis[v]) { q.push(v); vis[v]=true; } } } } } void print() { int ans=0; for(int i=1;i<=n;i++) minn[i]=min(minn[i],a1[i]); for(int i=1;i<=n;i++) { if(maxn[i]-minn[i]>ans) ans=maxn[i]-minn[i]; } cout<<ans<<endl; } void solve() { spfa1(); spfa2(); print(); } int main() { memset(head,-1,sizeof(head)); memset(headf,-1,sizeof(headf)); read(); solve(); return 0; }
---QQ:2602626065