bzoj3112: [Zjoi2013]防守戰線
阿新 • • 發佈:2019-01-01
最長路徑 stdin 學習 font sin 流量 有一個 bzoj3112 nod
學習了一下費用流的做法,順便學習了一下zkw(聽說原始對偶是折中做法,這種沒什麽特點的就不學了),順便研究了一下費用流的速度:(對於這題而言)
解決線性規劃還是單純形法優秀啊
zkw費用流適用費用值域較小,增廣路徑較短的圖(二分圖)
然後類似KM的寫法是不資瓷邊權為負的(懵逼)因為我嘗試寫了一會樣例都過不了
然而實際上構出最長路徑樹直接跑最大費用最大流就好了。。。。
對於這道題費用流的做法:
還是先把原始問題轉換成對偶問題(假如不轉對偶應該也是同理的推),註意此時系數和約束常數項就互換了,也就是費用和至少安插的塔可以理解為互換了
此時把約束差分。差分有一個很優美的性質,每個柿子會被加一次減一次,如果我們把每個約束看成一個點,變量相當於流到這個約束又流走
那麽把式子加起來每個變量和常數和等於0,聯想到網絡流的流量平衡
我們得到如下建圖方法:
1:差分後的常數項若大於0,就從st連一條流量為該值費用無限的邊,反之從該約束連向ed連一條流量為該值相反數費用無限的邊,常數平衡
2:對於一個變量,差分後他是正值的約束連向差分後他是負值的約束,變量平衡
3:差分後相鄰的兩個約束由前一個連向後一個,流量無限費用為0:處理松弛變量的影響,和2同理
最後跑最大費用最大流
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include單純形<algorithm> #include<cmath> using namespace std; const double eps=1e-7; int n,m; double sum; double a[1100][11000],b[11000],c[1100]; void pivot(int o,int e) { c[o]/=a[o][e]; for(int i=1;i<=m;i++) if(i!=e)a[o][i]/=a[o][e]; a[o][e]=1/a[o][e]; for(int i=1;i<=n;i++) if(i!=o&&fabs(a[i][e])>eps) { c[i]-=c[o]*a[i][e]; for(int j=1;j<=m;j++) if(j!=e)a[i][j]-=a[o][j]*a[i][e]; a[i][e]*=-a[o][e]; } sum+=b[e]*c[o]; for(int i=1;i<=m;i++) if(i!=e)b[i]-=a[o][i]*b[e]; b[e]*=-a[o][e]; } void simplex() { int e,o; double d; while(1) { d=0; for(int i=1;i<=m;i++) if(b[i]>d)d=b[i],e=i; if(d==0)return ; d=(1<<30); for(int i=1;i<=n;i++) if(a[i][e]>eps&&d>c[i]/a[i][e]) d=c[i]/a[i][e],o=i; if(d==(1<<30)){sum=(1<<30);return ;} pivot(o,e); } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int l,r; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lf",&c[i]); memset(a,0,sizeof(a)); for(int i=1;i<=m;i++) { scanf("%d%d%lf",&l,&r,&b[i]); for(int j=l;j<=r;j++)a[j][i]++; } simplex(); printf("%.0lf\n",sum); return 0; }
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30)-1; struct node { int x,y,c,d,next; }a[310000];int len,last[21000]; void ins(int x,int y,int c,int d) { len++; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; len++; a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; } int st,ed; int pre[21000],c[21000],ans,d[21000]; int list[21000];bool v[21000]; bool spfa() { memset(d,63,sizeof(d));d[st]=0;c[st]=(1<<30); memset(v,false,sizeof(v));v[st]=true; int head=1,tail=2;list[1]=st; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]>d[x]+a[k].d) { d[y]=d[x]+a[k].d; c[y]=min(a[k].c,c[x]); pre[y]=k; if(v[y]==false) { v[y]=true; list[tail]=y; tail++;if(tail==20100)tail=1; } } } v[x]=false; head++;if(head==20100)head=1; } if(d[ed]==d[0])return false; else { int y=ed;ans+=c[ed]*d[ed]; while(y!=st) { int k=pre[y]; a[k].c-=c[ed]; a[k^1].c+=c[ed]; y=a[k].x; } return true; } } int p[1100]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m; scanf("%d%d",&n,&m); st=n+2,ed=n+3; len=1; for(int i=1;i<=n;i++) scanf("%d",&p[i]),ins(i,i+1,inf,0); for(int i=1;i<=n+1;i++) if(p[i]-p[i-1]>0)ins(st,i,p[i]-p[i-1],0); else ins(i,ed,p[i-1]-p[i],0); int l,r,d; for(int i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&d); ins(l,r+1,inf,-d); } while(spfa()); printf("%d\n",-ans); return 0; }MCMF
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30)-1; struct node { int x,y,c,d,next; }a[210000];int len,last[1100]; void ins(int x,int y,int c,int d) { len++; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; len++; a[len].y=x;a[len].x=y;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; } int st,ed; int head,tail,list[110000]; bool v[1100]; int d[1100]; bool spfa() { memset(v,false,sizeof(v));v[ed]=true; memset(d,-63,sizeof(d));d[ed]=0; head=50001,tail=50002;list[head]=ed; while(head!=tail) { int x=list[head];v[x]=false; head++;if(head==105000)head=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k^1].c>0&&d[y]<d[x]+a[k^1].d) { d[y]=d[x]+a[k^1].d; if(v[y]==false) { v[y]=true; if(d[y]<d[list[head]]) { head--;if(head==0)head=104999; list[head]=y; } else { list[tail]=y; tail++;if(tail==105000)tail=1; } } } } } return d[st]>d[0]; } int ans; int findflow(int x,int f) { if(x==ed)return f; int s=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false&&d[x]-a[k].d==d[y]&&a[k].c>0&&s<f) { v[y]=true; int t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[k^1].c+=t; ans+=a[k].d*t; } } return s; } int c[1100]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m; scanf("%d%d",&n,&m); st=n+2,ed=n+3; len=1; for(int i=1;i<=n;i++) scanf("%d",&c[i]),ins(i,i+1,inf,0); for(int i=1;i<=n+1;i++) if(c[i]-c[i-1]>0)ins(st,i,c[i]-c[i-1],0); else ins(i,ed,c[i-1]-c[i],0); int l,r,d; for(int i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&d); ins(l,r+1,inf,d); } int flow=0; ans=0; while(spfa()) { do { memset(v,false,sizeof(v));v[st]=true; flow+=findflow(st,inf); }while(v[ed]==true); } printf("%d\n",ans); return 0; }zkw(SLF優化)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const int inf=(1<<30)-1; struct node { int x,y,c,d,next; }a[210000];int len,last[1100]; void ins(int x,int y,int c,int d) { len++; a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d; a[len].next=last[x];last[x]=len; len++; a[len].y=x;a[len].x=y;a[len].c=0;a[len].d=-d; a[len].next=last[y];last[y]=len; } int st,ed; int head,tail,list[1100]; bool v[1100]; int d[1100]; void spfa() { memset(v,false,sizeof(v));v[ed]=true; memset(d,-63,sizeof(d));d[ed]=0; head=1,tail=2;list[head]=ed; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k^1].c>0&&d[y]<d[x]+a[k^1].d) { d[y]=d[x]+a[k^1].d; if(v[y]==false) { v[y]=true; list[tail]=y; tail++;if(tail==1050)tail=1; } } } v[x]=false; head++;if(head==1050)head=1; } } int ans; int findflow(int x,int f) { if(x==ed){ans+=d[st]*f;return f;} int s=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false&&d[x]-a[k].d==d[y]&&a[k].c>0&&s<f) { v[y]=true; int t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[k^1].c+=t; } } return s; } bool adjust() { int tmp=inf; for(int x=1;x<=ed;x++) if(v[x]==true) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false&&a[k].c>0) tmp=min(tmp,d[x]-(d[y]+a[k].d)); } } if(tmp==inf)return false; for(int i=1;i<=ed;i++) if(v[i]==true)d[i]-=tmp; return true; } int c[1100]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m; scanf("%d%d",&n,&m); st=n+2,ed=n+3; len=1; for(int i=1;i<=n;i++) scanf("%d",&c[i]),ins(i,i+1,inf,0); for(int i=1;i<=n+1;i++) if(c[i]-c[i-1]>0)ins(st,i,c[i]-c[i-1],0); else ins(i,ed,c[i-1]-c[i],0); int l,r,dd; for(int i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&dd); ins(l,r+1,inf,dd); } ans=0; spfa(); do { do { memset(v,false,sizeof(v));v[st]=true; }while(findflow(st,inf)); }while(adjust()); printf("%d\n",ans); return 0; }zkw(KM)
bzoj3112: [Zjoi2013]防守戰線