1. 程式人生 > >洛谷 P1073 最優貿易

洛谷 P1073 最優貿易

題目:最優貿易

思路:
tarjan+dp。
要注意縮點後仍要判斷每個點是否可達終點。

程式碼:

#include<bits/stdc++.h>
using namespace std;

#define maxn 100000
#define maxm 500000
#define read(x) scanf("%d",&x)

int n,m;
int w[maxn+5];
vector<int> a[maxn+5];

int pre[maxn+5]= {0},low[maxn+5],clk=0;
stack<int> s;
int cnt=0,isin[maxn+5];
vector<int> g[maxn+5]; int val[maxn+5]= {0},val2[maxn+5]; int vis[maxn+5]= {0}; bool canuse[maxn+5]= {0}; int isout; void tarjan(int x) { pre[x]=low[x]=++clk; s.push(x); for(int i=0; i<a[x].size(); i++) { int y=a[x][i]; if(!pre[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else
if(!isin[y]) { low[x]=min(low[x],pre[y]); } } if(pre[x]==low[x]) { cnt++; int u; val2[cnt]=1e9; do { u=s.top(); s.pop(); if(u==n) isout=cnt; isin[u]=cnt; val[cnt]=max(w[u],val[cnt]); val2[cnt]=min(w[u],val2[cnt]); } while(u!=x); } } void make_g() { for(int i=1;
i<=n; i++) { for(int j=0; j<a[i].size(); j++) { if(isin[i]!=isin[a[i][j]]) { g[isin[i]].push_back(isin[a[i][j]]); } } } } void dfs(int x) { if(vis[x]||!canuse[x]) return ; vis[x]=val[x]; for(int i=0; i<g[x].size(); i++) { int y=g[x][i]; dfs(y); vis[x]=max(vis[x],vis[y]); } return ; } void readin() { read(n),read(m); for(int i=1; i<=n; i++) read(w[i]); for(int i=1; i<=m; i++) { int x,y,opr; read(x),read(y),read(opr); a[x].push_back(y); if(opr==2) a[y].push_back(x); } } bool find(int x) { if(x==isout) return canuse[x]=true; if(vis[x]) return canuse[x]; vis[x]=true; for(int i=0; i<g[x].size(); i++) { int y=g[x][i]; canuse[x]=max(find(y),canuse[x]); } return canuse[x]; } int main() { readin(); for(int i=1;i<=n;i++) if(!pre[i]) tarjan(i); make_g(); for(int i=1;i<=cnt;i++) { if(!vis[i]) find(i); } memset(vis,0,sizeof(vis)); for(int i=1; i<=cnt; i++) { if(!vis[i]) dfs(i); } int ans=0; for(int i=1; i<=cnt; i++) { ans=max(ans,vis[i]-val2[i]); } printf("%d",ans); return 0; }