luogu P3980 [NOI2008]誌願者招募
阿新 • • 發佈:2019-01-15
oid cas 聯系 cpp clas () long long 常數 i+1 的式子),然後得到\(n+1\)個等式.每個等式再移項,使得系數全為正數.我們發現每個變量分別在某個等式左邊出現一次,也在某個右邊出現一次.所以可以聯系網絡流是流入流量=流出流量的,這裏把每個等式看做一個點,左邊看做流入,右邊看做流出.對於變量\(x_i\),從流出的點向流入的點連流量為能用的最大次數(本題為Inf),費用為單個代價的邊;對於變量\(y_i\),從流出的點向流入的點連流量為能用的最大次數(本題為Inf),費用為0的邊;對於常數項\(a_i\),從原點向流入點連流量Inf費用0邊,從流出點向匯點連流量Inf費用0邊,然後費用流求費用就好了
傳送門
網絡流又一神仙套路應用
首先考慮列不等式,設\(x_i\)為第i種人的個數,記\(b_{i,j}\)為第i種人第j天是否能工作,那麽可以列出n個不等式,第j個為\(\sum_{i=1}^{m}b_{i,j}x_i\ge a_j\)
然後將這些不等式轉成等式,新開變量y,則那些不等式可以寫為\[\begin{cases}b_{1,1}x_1+b_{2,1}x_2...+b_{m,1}x_m=a_1+y_1\\b_{1,2}x_1+b_{2,2}x_2...+b_{m,2}x_m=a_2+y_2\\......\end{cases}\]
然後每個式子都減去上面的式子(假裝最後有一個\(0=0\)
感性理解一下?(
#include<bits/stdc++.h> #define LL long long #define il inline #define re register #define db double using namespace std; const int N=1e4+10,M=1e5+10; il int rd() { int x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int n,m; int a[N],b[N][3]; int ps,pt,to[M],nt[M],c[M],hd[N],tot=1; LL w[M]; il void add(int x,int y,int z,int zz) { ++tot,to[tot]=y,nt[tot]=hd[x],c[tot]=z,w[tot]= zz,hd[x]=tot; ++tot,to[tot]=x,nt[tot]=hd[y],c[tot]=0,w[tot]=-zz,hd[y]=tot; } LL di[N],ans; int pre[N],fw[N]; bool v[N]; queue<int> q; il bool csfl() { memset(di,0x3f3f3f,sizeof(di)); memset(fw,0,sizeof(fw)); di[ps]=0,fw[ps]=1<<30,v[ps]=1,q.push(ps); while(!q.empty()) { int x=q.front(); q.pop(); for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(c[i]>0&&di[y]>di[x]+w[i]) { di[y]=di[x]+w[i]; pre[y]=i,fw[y]=min(fw[x],c[i]); if(!v[y]) v[y]=1,q.push(y); } } v[x]=0; } if(di[pt]==di[pt+1]) return 0; ans+=1ll*di[pt]*fw[pt]; int x=pt; while(x^ps) { int i=pre[x]; c[i]-=fw[pt],c[i^1]+=fw[pt]; x=to[i^1]; } return 1; } int main() { n=rd(),m=rd(); for(int i=1;i<=n;++i) a[i]=rd(); for(int i=1;i<=m;++i) b[i][0]=rd(),b[i][1]=rd(),b[i][2]=rd(); ps=0,pt=n+3; for(int i=1;i<=m;++i) add(b[i][1]+1,b[i][0],1<<30,b[i][2]); for(int i=1;i<=n;++i) add(i,i+1,1<<30,0); for(int i=1;i<=n;++i) add(ps,i+1,a[i],0),add(i,pt,a[i],0); while(csfl()); printf("%lld\n",ans); return 0; }
luogu P3980 [NOI2008]誌願者招募