• P1251 餐巾计划问题


    因为脏的衣服在一天结束时才会有,干净的一天开始才会有,考虑拆点。

    再考虑干净的衣服都是要被收集起来的,所以干净的要流向超汇。而脏的衣服可以从超源免费获得所需要的个数,而干净的衣服只能购买。

    看张图吧,假如只有 1 个点的话,且需要无限多的衣服。

    显然前者正确,后者矛盾(收集了脏衣服)

    再者,这种建图会无法收集到当天的脏衣服。

    假如从 T 点再回来也不现实,所以只能从 S 供给了。

    因为最后一定满流,所以从 S 供给脏衣服是正确的。

    #include <bits/stdc++.h>
    using namespace std;
    int rd() {
        int f=1,sum=0; char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
        while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
        return sum*f;
    }
    
    #define int long long
    #define N (int)(4e4+5)
    #define inf (int)(2e18)
    struct edge {
    	int nex,to,w,c;
    }e[N<<1];
    int hea[N],cnt=1;
    int n,S,T,ans;
    
    void add_edge(int x,int y,int z,int c) {
    	e[++cnt].nex=hea[x]; e[cnt].to=y; e[cnt].w=z; e[cnt].c=c; hea[x]=cnt;
    }
    
    void add(int x,int y,int z,int c) {
    	add_edge(x,y,z,c);
    	add_edge(y,x,0,-c);
    }
    
    deque<int>q;
    bool vis[N];
    int dis[N];
    bool spfa() {
    	for(int i=0;i<N;i++) dis[i]=inf,vis[i]=0;
    	q.push_back(S); dis[S]=0;
    	while(!q.empty()) {
    		int x=q.front(); q.pop_front();
    		vis[x]=0;
    		for(int i=hea[x];i;i=e[i].nex) {
    			int y=e[i].to;
    			if(e[i].w&&dis[y]>dis[x]+e[i].c) {
    				dis[y]=dis[x]+e[i].c;
    				if(!vis[y]) {
    					vis[y]=1;
    					if(!q.empty()&&dis[y]<dis[q.front()]) q.push_front(y);
    					else q.push_back(y);
    				}
    			}
    		}
    	}
    	return dis[T]<inf;
    }
    
    int dfs(int x,int lim) {
    	if(x==T||!lim) return lim;
    	int flow=0,fl;
    	vis[x]=1;
    	for(int i=hea[x];i&&lim;i=e[i].nex) {
    		int y=e[i].to;
    		if(e[i].w&&!vis[y]&&dis[y]==dis[x]+e[i].c) {
    			fl=dfs(y,min(lim,e[i].w));
    			if(!fl) continue;
    			flow+=fl; lim-=fl; e[i].w-=fl; e[i^1].w+=fl;
    			ans+=e[i].c*fl;
    		}
    	}
    	if(!flow) dis[x]=inf;
    	vis[x]=0;
    	return flow;
    }
    
    void dinic() {
    	while(spfa()) {
    		memset(vis,0,sizeof(vis));
    		dfs(S,inf);
    	}
    }
    int a[N];
    signed main() {
    	int x,y;
    	n=rd(); S=0; T=2*n+1;
    	for(int i=1;i<=n;i++) {
    		a[i]=rd();
    		add(S,i+n,a[i],0); add(i,i+n,inf,0); add(i,T,a[i],0);
    	}
    	x=rd();
    	for(int i=1;i<=n;i++) add(S,i,inf,x);
    	x=rd(); y=rd();
    	for(int i=1;i<=n;i++) {
    		if(i+x<=n) add(i+n,i+x,inf,y);
    	}
    	x=rd(); y=rd();
    	for(int i=1;i<=n;i++) {
    		if(i+x<=n) add(i+n,i+x,inf,y);
    	}
    	for(int i=1;i<n;i++) add(i+n,i+n+1,inf,0);
    	dinic();
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    块结构在文件中的表示IOB【转载】
    LSTM输入层、隐含层及输出层参数理解【转载】
    L3-002 特殊堆栈 (30 分) 模拟stl
    L1-006 连续因子 (20 分) 模拟
    L2-014 列车调度 (25 分)
    L3-021 神坛 (30 分) 计算几何
    P1156 垃圾陷阱 DP
    P1063 能量项链 区间dp
    P1040 加分二叉树 区间dp
    P1605 迷宫 dfs回溯法
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15872323.html
Copyright © 2020-2023  润新知