zoukankan      html  css  js  c++  java
  • P1251 餐巾计划问题

    看到数据很小,且 (DP) 很难记录状态的题大概就是网络流量了,可以用网络流想一下

    首相考虑费用流的特性,流量会流满,利用这一点,我们可以满足每天需要的餐巾纸都能被提供

    考虑餐巾纸用过后会变成脏餐巾纸,利用流量的特性将没洗的留给第二天,但是这有出现了一个问题,每天,既用卫生纸,又产生脏卫生纸,这两种纸肯定不能和在一起,而且如果设用纸巾是用掉流量的话,就需要 (S) 再连入额外的流量

    这时一个点已经无法处理了,因为每天用多少纸是固定的,所以将一个点拆成两个,早上和晚上,早上用纸,晚上产生纸和处理洗纸,对应到图上是这样的

    • 一个点分成早上和晚上 (x, x')
    • 每天可以购买新纸,(S o x)
    • 必需要用纸 (x o T)
    • 产生脏纸 (S o x')
    • 脏纸留给明天 (x' o (x+1)')
    • 清洗脏纸 (x' o (x + a))
    #include<bits/stdc++.h>
    using namespace std;
    #define rg register
    inline int read(){
    	rg char ch=getchar();
    	rg int x=0,f=0;
    	while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=4005,M=N<<3;
    int head[N],ver[M],nxt[M],edge[M],flow[M],tot=1;
    inline void add(int x,int y,int z,int f){
    	ver[++tot]=y;
    	edge[tot]=z;
    	flow[tot]=f;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    inline void adds(int x,int y,int z,int f){
    	add(x,y,z,f);
    	add(y,x,-z,0);
    }
    int q;
    int nd[N];
    int P,MM,F,NN,S;
    int s,t;
    int dis[N],pre[N],vis[N];
    #define inf 0x3f3f3f3f
    inline int spfa(){
    	queue<int> q;
    	q.push(s);
    	memset(dis,0x3f,sizeof dis);
    	memset(vis,0,sizeof vis);
    	dis[s]=0;
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		vis[x]=false;
    		for(int y,i=head[x];i;i=nxt[i]){
    			y=ver[i];
    			if(dis[y]>dis[x]+edge[i]&&flow[i]){
    				dis[y]=dis[x]+edge[i];
    				pre[y]=i;
    				if(!vis[y]){
    					vis[y]=true;
    					q.push(y);
    				}
    			}
    		}
    	}
    	return dis[t]^0x3f3f3f3f;
    }
    template <typename T>
    inline void ckmin(T &a,const T &b){
    	if(a>b) a=b;
    }
    inline long long EK(){
    	int minflow;
    	long long ans=0;
    	while(spfa()){
    		minflow=0x3f3f3f3f;
    		for(int i=pre[t];i;i=pre[ver[i^1]])
    			ckmin(minflow,flow[i]);
    		ans+=dis[t]*minflow;
    		for(int i=pre[t];i;i=pre[ver[i^1]])
    			flow[i]-=minflow,flow[i^1]+=minflow;
    	}
    	return ans;
    }
    signed main(){
    	q=read();
    	s=0,t=q<<1|1;
    	for(int i=1;i<=q;++i) nd[i]=read(),adds(s,i<<1,0,nd[i]);
    	P=read(),MM=read(),F=read(),NN=read(),S=read();
    	for(int i=1;i<=q;++i){
    		adds(s,(i<<1)-1,P,nd[i]);
    		adds((i<<1)-1,t,0,nd[i]);
    		if(i+MM<=q) adds(i<<1,(i+MM<<1)-1,F,inf);
    		if(i+NN<=q) adds(i<<1,(i+NN<<1)-1,S,inf);
    		if(i^q) adds(i<<1,i+1<<1,0,inf);
    	}
    	cout<<EK()<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    linux中的cd ..和cd -命令有什么区别?
    GCC使用
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13098532.html
Copyright © 2011-2022 走看看