• BZOJ-1221 软件开发


    这题是基于一道经典的费用流模型。

    将每天拆成两个点i和j,新增源和汇并建立六种边:

    1.从源出发到每个i点,flow为+∞,cost为每条新餐巾的价值,表示这一天所使用的餐巾中来自购买的餐巾

    2.从源出发到每个j点,flow为每天所需的餐巾数,cost为0,表示这一天最多可使用的餐巾

    3.从每个i点出发至汇,flow为每天所需的餐巾数,cost为0,表示这一天应该使用的餐巾

    4.从每个j点出发至下一个j点,flow为+∞,cost为0,表示这一天使用后的餐巾移至下一天

    5.从每个j点出发至下a个i点,flow为+∞,cost为第一种消毒的费用,表示这一天所使用的餐巾中来自第一种消毒后的餐巾

    6.从每个j点出发至下b个i点,flow为+∞,cost为第二种消毒的费用,表示这一天所使用的餐巾中来自第二种消毒后的餐巾

    然后最小费用最大流跑之。

    基于图的稀疏,我用ZKW费用流实现。

    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <deque>
    using namespace std;
    typedef long long ll;
    #define rep(i, l, r) for(int i=l; i<=r; i++)
    #define clr(x, c) memset(x, c, sizeof(c))
    #define travel(x) for(edge *p=fir[x]; p; p=p->n) if (p->f)
    #define pb push_back
    #define pf push_front
    #define maxv 2009
    #define maxm 30009
    #define inf 0x7fffffff
    int read()
    {
    	int x=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    	return x;
    }
    
    
    struct edge{int y, f, c; edge *n, *pair;} e[maxm], *fir[maxv], *pt;
    inline void Init(){pt=e; clr(fir, 0);}
    inline void Add(int x, int y, int f, int c)
    	{pt->y=y, pt->f=f, pt->c=c, pt->n=fir[x]; fir[x]=pt++;}
    inline void AddE(int x, int y, int f, int c)
    	{Add(x, y, f, c); Add(y, x, 0, -c); fir[x]->pair=fir[y], fir[y]->pair=fir[x];}
    int S, T, V, d[maxv]; ll cost=0;
    int dist[maxv], st[maxv];
    bool b[maxv];
    deque <int> q;
    inline void spfa()
    {
    	rep(i, 1, V) d[i]=inf, b[i]=0; q.clear();
    	q.pb(S), d[S]=0, b[S]=1;
    	while (!q.empty())
    	{
    		int x=q.front(), y; q.pop_front(); b[x]=0;
    		travel(x) if (d[y=p->y] > d[x]+p->c) 
    		{
    			d[y]=d[x]+p->c; 
    			if (!b[y]) b[y]=1, (!q.empty() && d[q.front()]>d[y]) ? q.pf(y) : q.pb(y);
    		}
    	}
    }
    void dfs(int now)
    {
    	b[now]=1; int y;
    	travel(now) 
    		if (d[now]+p->c==d[y=p->y] && !b[y]) 
    			dist[y]=dist[now]-p->c, dfs(y);
    }
    int aug(int now, int flow)
    {
    	if (now==T) {cost+=flow*(dist[S]-dist[T]); return flow;}
    	b[now]=1; int rec=0, y, ret;
    	travel(now) if (!b[y=p->y])
    	{
    		if (dist[now]==dist[y]+p->c)
    		{
    			ret=aug(y, min(flow-rec, p->f));
    			p->f-=ret, p->pair->f+=ret;
    			if ((rec+=ret)==flow) return flow;
    		}
    		else st[y]=min(st[y], dist[y]+p->c-dist[now]);
    	}
    	return rec;
    }
    inline bool relabel()
    {
    	int a=inf;
    	rep(i, 1, V) if (!b[i]) a=min(a, st[i]);
    	if (a==inf) return 0;
    	rep(i, 1, V) if (b[i]) dist[i]+=a;
    	return 1;
    }
    inline void costflow()
    {
    	spfa();
    	clr(b, 0); clr(dist, 0); 
    	dfs(S);
    	while(1)
    	{
    		rep(i, 1, V) st[i]=inf;
    		while(1) 
    		{
    			rep(i, 1, V) b[i]=0;//clr(b, 0);
    			if (!aug(S, inf)) break;
    		}
    		if (!relabel()) break;
    	}
    }
    
    
    
    int n;
    int main(){
    	Init(); n=read(); S=n*2+1; T=V=n*2+2; 
    	int a=read(), b=read(), f=read(), fa=read(), fb=read();
    	rep(i, 1, n-a) AddE(i*2, (i+a+1)*2-1, inf, fa);
    	rep(i, 1, n-b) AddE(i*2, (i+b+1)*2-1, inf, fb);
    	rep(i, 1, n) a=read(), AddE(S, i*2-1, inf, f), AddE(S, i*2, a, 0), AddE(i*2-1, T, a, 0);
    	rep(i, 1, n-1) AddE(i*2, i*2+2, inf, 0);
    	costflow(); printf("%lld
    ", cost);
    	return 0;
    }
  • 相关阅读:
    采样定理
    空间谱专题03:时空特性与采样定理
    常见的矩阵形式
    【Windows】XShell中使用小键盘和ALT键(作Meta键),使BackSpace正常
    【Linux】Ubuntu13.10搭建gitlab报错信息及解决
    〖Android〗ant build android project, setting android.jar precedence
    〖Linux〗使用命令行切换触摸板的状态on/off/toggle
    【Android】ant编译aidl的错误
    【Android】源码external/目录中在编译过程中生成的文件列表
    〖Linux〗实时更新 hosts 文件的脚本
  • 原文地址:https://www.cnblogs.com/NanoApe/p/4445308.html
Copyright © 2020-2023  润新知