GMOJ 2429. 【NOI2008】志願者招募 題解
阿新 • • 發佈:2021-07-16
思路
oh,我可愛的一眼網路流題。
話說為什麼一天一道網路流
這個做法好像比較清奇。
非常清奇你根本找不到一樣的
之前口胡過最長 k 可重區間集 ,所以很快就有思路了。
首先對於區間 \([l,r]\) ,我們把 \(l\) 與 \(r+1\) 連一條無限流量輸入費用的邊。
然後考慮因為是至少覆蓋所以志願者(流量)不能在區間不覆蓋時移動,但是顯然區間會重。
於是我們對於每一個點 \(i\) 向 \(i-1\) 連一條無限流量無費用的邊,讓流量可以在兩個重疊區間中移動。
再考慮每天人數不一樣,這個比較顯然,需要就從源點補,多了就退給匯點。
顯然匯點直接為 \(n+1\) 這樣減少一些處理。
如樣例建圖為:
CODE
因為資料比較大寫了一個 SPFA-PMF 核心的 Primal-Dual 原始對偶演算法優化 zkw 費用流。
事實證明並不需要。
#include<ctime> #include<cstdio> #include<cstring> #include<iostream> #define reg register #define uni unsigned #define ll long long using namespace std; const int N=1010,M=40010,FSIZE=1<<20,INF=0x7f7f7f7f,W=4; int n,m,d[N<<3],a[N],last,map[N]; struct edge{ int l,t;ll v,c; }e[M]; ll ht[N],w[N],mincost; bool vis[N]; char BuF[FSIZE],*InF=BuF; template<typename T>void read(T &x){ for(;47>*InF||*InF>58;++InF); for(x=0;47<*InF&&*InF<58;x=x*10+(*InF++^48)); } void add(int x,int y,int z,ll c){ e[last]=(edge){a[x],y,z,c}; a[x]=last++; } void Add(int x,int y,int z,ll c){ add(x,y,z,c); add(y,x,0,-c); } void spfa(){ memset(ht,127,sizeof(ht)); for(reg int h=0,t=ht[0]=0;h<=t;++h){ reg int hd=d[h]; for(reg int i=a[hd];~i;i=e[i].l){ reg int to=e[i].t;ll p=ht[hd]+e[i].c; if(e[i].v&&ht[to]>p){ ht[to]=p; if(!vis[to]) vis[d[++t]=to]=1; } } vis[hd]=0; } } uni seed=time(0); int rnd(const int &l,const int &r){ seed^=seed<<17;seed^=seed>>13;seed^=seed>>5; return(seed%(r-l+1)+l); } void change(int &x,int &y){ swap(map[x],map[y]); swap(x,y); } bool spfa_PMF(){ memset(w,127,sizeof(w)); for(reg int h=0,t=w[0]=0;h<=t;++h){ reg int &hd=d[h]; for(reg int i=0,*zh=d+h+1,*tl=d+t;i<W&&zh<tl;++i,++zh,--tl){ if(w[hd]>w[*zh]) change(hd,*zh); if(w[hd]>w[*tl]) change(hd,*tl); } for(reg int i=a[hd];~i;i=e[i].l){ reg int to=e[i].t;ll p=w[hd]+e[i].c+ht[hd]-ht[to]; if(e[i].v&&w[to]>p){ w[to]=p; if(!map[to]){ d[map[to]=++t]=to; if(t>h+1&&w[d[t]]>w[d[t-1]]) change(d[t],d[t-1]); }else if(w[to]<w[d[t]]) change(d[map[to]],d[t]); } } map[hd]=vis[hd]=0; } return(w[n+1]<INF); } int dfs(int x,ll flow){ if(x==n+1||!flow) return(flow); vis[x]=1; ll aflow,used=0; for(int i=a[x];~i;i=e[i].l){ edge &g=e[i]; if(!vis[g.t]&&g.v&&w[x]+g.c+ht[x]-ht[g.t]==w[g.t]&&(aflow=dfs(g.t,min(g.v,flow-used)))){ g.v-=aflow; e[i^1].v+=aflow; mincost+=aflow*g.c; if((used+=aflow)==flow) break; } } return(used); } void PMF_SSP(){ for(spfa();spfa_PMF();){ dfs(0,INF); for(reg int i=0;i<=n+1;++i) if(w[i]<INF) ht[i]+=w[i]; } } int main(){ fread(BuF,1,FSIZE,stdin); memset(a,-1,sizeof(a)); read(n);read(m); read(d[1]); Add(0,1,d[1],0); for(reg int i=2;i<=n;++i){ read(d[i]); Add(i,i-1,INF,0); if(d[i]>d[i-1]) Add(0,i,d[i]-d[i-1],0); else Add(i,n+1,d[i-1]-d[i],0); } for(reg int x,y,z;m;--m){ read(x);read(y);read(z); Add(x,y+1,INF,z); } PMF_SSP(); printf("%lld",mincost); return(0); }