P1073题解
题目链接
其实这道题本来应该是一道tarjan缩点+DAG题的,但是有一种更优的方法,即分层图+SPFA.这里我们把图复制两份,即两层,每层图之间点与点之间的关系都是一样的,并且边权都为0.
这三层图第一层图表示没有买入时候的图,第二层图表示买入但还没有卖出的图,第三层图表示已经卖出的图.这样分可以避免无限卖出. 对于第一层和第二层的每个点,两层之间应该是有向边,并且边权应该为价格的负数倍,毕竟买东西肯定要花钱.那么同理卖东西就要加钱.最后我们跑一次SPFA,然后找第三层图的n号节点就可以了.
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
struct node{int u,v;
};
int n,m,x,y,z,f[N],dis[N];
int t(int x, int y){return x*n+y;}
vector<node>v[N];
void add(int x, int y, int w){v[x].push_back({y,w});
}
void SPFA(){queue<int>q;for(int i=2;i<=3*n;i++) dis[i]=(-1e9);f[t(0,1)]=1, q.push(t(0,1));while(q.size()){int t2=q.front();q.pop(), f[t2]=0;for(int i=0;i<v[t2].size();i++){int u=v[t2][i].u, w=v[t2][i].v;if(dis[t2]+w>dis[u]){dis[u]=dis[t2]+w;if(!f[u]) q.push(u), f[u]=1;}}}
}
signed main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>x;add(t(0,i),t(1,i),-x), add(t(1,i),t(2,i),x);}while(m--){cin>>x>>y>>z;if(z==1){for(int i=0;i<=2;i++) add(t(i,x),t(i,y),0);}else{for(int i=0;i<=2;i++){add(t(i,x),t(i,y),0);add(t(i,y),t(i,x),0);}}}SPFA();if(dis[t(2,n)]==(-1e9)) cout<<0;else cout<<dis[t(2,n)];return 0;
}