1. 程式人生 > >餐巾計劃問題

餐巾計劃問題

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);
}

餐巾計劃問題