P1073 最優貿易 分層圖+最長路
阿新 • • 發佈:2020-09-04
洛谷p1073 最優貿易
連結
首先易得暴n2的暴力,暴力列舉就行
顯然1e5的資料是會炸的
我們再分析題意,發現一共分為兩個個步驟,也可以說是狀態,即在一個點買入,在另一個點賣出,我們可以構建一個三層分層圖
第一層的每個點和第二層的對應點各連線一條權值為-val[i](val[i]表示i號點的水晶價格)的單向邊
表示在i號點買進,
再在第二層的每個點向第三層的對應點各連線一條權值為val[j]的有向邊
表示在j號點賣出,
構建好分層圖後
我們在分層圖上跑最長路
以第三層中的n號點為終點
便可求解
即使有負權,可我們因為跑的是最長路
所以dijistla不受影響
ac程式碼如下
時間複雜度邊為3mlog3m
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<queue> #define inf -0x3f3f3f3f using namespace std; const int maxn=5e5; inline int read(){ int ret=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-f; ch=getchar(); } while(ch>='0'&&ch<='9'){ ret=ret*10+(ch^'0'); ch=getchar(); } return f*ret; } struct edge{ int nex; int to; int v; }e[maxn*3]; struct node{ int u,d; bool operator <(const node &x) const{ return x.d<d; } }; int head[maxn*3]; int cnt; void add(int u,int to,int v){ cnt++; e[cnt].nex=head[u]; e[cnt].to=to; e[cnt].v=v; head[u]=cnt; } int n,m; int dis[maxn*3]; int val[maxn]; inline void di(int s){ for(int i=1;i<=n;i++){ dis[i]=inf; } dis[s]=0; priority_queue<node>q; q.push((node){s,0}); while(!q.empty()){ node f=q.top(); q.pop(); int u=f.u; int d=f.d; if(dis[u]!=d) continue; for(int i=head[u];i;i=e[i].nex){ int v=e[i].v; int y=e[i].to; if(dis[u]+v>dis[y]){ dis[y]=dis[u]+v; q.push((node){y,dis[y]}); } } } } int main(){ // freopen("a.in","r",stdin); n=read(); m=read(); for(int i=1;i<=n;i++){ val[i]=read(); add(i,i+n,-val[i]); add(i+n,+2*n+i,val[i]); } int x,y,z; for(int i=1;i<=m;i++){ x=read(); y=read(); z=read(); add(x,y,0); add(x+n,y+n,0); add(x+2*n,y+2*n,0); if(z==2){ add(y,x,0); add(y+n,x+n,0); add(y+2*n,x+2*n,0); } } n=n*3; di(1); cout<<dis[n]; return 0; }
結束嘍!