餐巾計劃問題
阿新 • • 發佈:2018-07-05
ons turn include 流量 long queue ++ std span
費用流
建圖很巧妙的感覺。。。
給每個點向拆成兩個點Xi,Yi
S->\(X_i\),流量r[i],費用0
\(Y_i\)->T,流量r[i],費用0
S->\(Y_i\),流量INF,費用p
\(X_i->X_{i+1}\),流量INF,費用0
\(X_i->Y_{i+m}\),流量INF,費用f
\(X_i->Y_{i+n}\),流量INF,費用s
跑一邊即可(記得開long long)
#include <queue> #include <cstdio> #include <cstring> #define int long long using namespace std; const int inf=0x3f3f3f3f3f3f3f3f,S=0,T=10003; int N; int a[10005],p,m,f,n,s,head[10005],ecnt=1,dis[10005],from[10005],mincost; bool inq[10005]; struct Edge{ int to,nxt,val,cost,from; }e[1000010]; void add(int bg,int ed,int val,int cost){e[++ecnt].cost=cost;e[ecnt].from=bg;e[ecnt].nxt=head[bg];e[ecnt].to=ed;e[ecnt].val=val;head[bg]=ecnt;} //l¥d$¥ void insert(int bg,int ed,int val,int cost){add(bg,ed,val,cost);add(ed,bg,0,-cost);} queue<int>q; bool spfa(){ q.push(S); std::memset(dis,0x3f,sizeof dis); std::memset(inq,0,sizeof inq); dis[S]=0;inq[S]=1; while(!q.empty()){ int u=q.front();q.pop();inq[u]=0; for(int i=head[u],v;i;i=e[i].nxt){ v=e[i].to; if(dis[v]>dis[u]+e[i].cost&&e[i].val){ dis[v]=dis[u]+e[i].cost; from[v]=i; if(!inq[v]) q.push(v),inq[v]=1; } } } return dis[T]!=inf; } void min(int &x,int y){x=x<y?x:y;} void mcf() { int x=inf,i=from[T]; while(i) {min(x,e[i].val);i=from[e[i].from];} i=from[T]; while(i){ e[i].val-=x;e[i^1].val+=x; mincost+=x*e[i].cost;i=from[e[i].from]; } } main(){ scanf("%lld",&N); for(int i=1;i<=N;i++) scanf("%lld",&a[i]); scanf("%lld%lld%lld%lld%lld",&p,&m,&f,&n,&s); for(int i=1;i<=N;i++) { insert(S,i,a[i],0); insert(i+N,T,a[i],0); if(i+1<=N) insert(i,i+1,inf,0); if(i+m<=N) insert(i,i+m+N,inf,f); if(i+n<=N) insert(i,i+n+N,inf,s); insert(S,i+N,inf,p); } while(spfa()) mcf(); printf("%lld",mincost); }
餐巾計劃問題