superoj441 餐巾计划

题目描述

输入格式

输入文件第 1 行有 6 个正整数 N,p,m,f,n,s。其中 N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n 是慢洗部洗一块餐巾需用天数;s 是慢洗部洗一块餐巾需要的费用。数据范围如下:1≤N≤800,1≤p≤50,1≤m≤20, 1≤f≤20,1≤n≤20,1≤s≤10。
接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数(每个数不超过500)。

输出格式

输出餐厅在相继的 N 天里使用餐巾的最小总花费。

样例数据 1

输入  [复制]

3 10 2 3 3 2 


7

输出

145

费用流

用类似于可重复背包删边

注意这坑题慢洗可能比快洗要快(坑哭我)

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;
struct node
{
   int to;
   int next;
   int liu;
   int cost;
   int from;
};
node bian[1300000];
int first[40010];
int dis[40010];
int xuqiu[40010]; 
int n,p,m,f,z,s;  //p新餐巾费用 m快洗time f快洗费用 z慢洗time s慢洗费用  
int size;
queue <int> q;
bool exsit[40000];
int zcost,zflow;
int pre[40000];

void inser(int a,int b,int liu,int cost)
{
	size++;
	bian[size].to=b;
	bian[size].next=first[a];
	first[a]=size;
	bian[size].liu=liu;
    bian[size].from=a;
    bian[size].cost=cost;
}

void init()
{
	int i,j;
    scanf("%d%d%d%d%d%d",&n,&p,&m,&f,&z,&s);
	for(i=1;i<=n;i++)
      {
         scanf("%d",&xuqiu[i]);	  
	  }
    for(i=1;i<=n;i++)
     {
     	inser(0,i,xuqiu[i],0);
     	inser(i,0,0,0);
     	
	 }
    for(i=1;i<=n;i++)
      {
      	inser(n+i,2*n+1,xuqiu[i],0);
      	inser(2*n+1,n+i,0,0);
	  }
    
    for(i=1;i<n;i++)
      {
      	inser(i,i+1,10000000,0);
      	inser(i+1,i,0,0);
	  }
    
    
 
    for(i=1;i<=n;i++)
      {  
        if(i+m<=n)
        {
		inser(i,i+n+m,10000000,f);
        inser(i+n+m,i,0,-f);
        }
        if(i+z<=n)
        {
		inser(i,i+n+z,10000000,s);
        inser(i+n+z,i,0,-s);
        }
		inser(0,n+i,10000000,p);
		inser(n+i,0,0,-p);  
	  }
    inser(4*n,0,100000000,0);
}

bool spfa()
{
	while(!q.empty()) q.pop();
    memset(dis,127,sizeof(dis));
    memset(exsit,false,sizeof(exsit));
    memset(pre,-1,sizeof(pre));
    pre[0]=size;   
	dis[0]=0;   	
	exsit[0]=true;
	q.push(0);
	
	while(!q.empty())
	  {
	  	 int u=q.front();
	  	 q.pop();
	  	 exsit[u]=false;
	  	 for(int i=first[u];i!=0;i=bian[i].next)
	  	   {
	  	   	   int d=bian[i].to;
	  	   	   if(bian[i].liu!=0&&dis[d]>dis[u]+bian[i].cost)
	  	   	      {
	  	   	         dis[d]=dis[u]+bian[i].cost;
				     pre[d]=i;		  					 
					 if(!exsit[d]) 
					   {
					   	  exsit[d]=true;
					   	 // if(exsit[n*2+1]) return true;
					   	  q.push(d);
					   }	  	 
				  }
		   }
	  }
    if(dis[2*n+1]>1000000000) return false;
	return true;
}




int flow_()
{
    int flow;
	while(spfa())
      {
      	flow=0x7fffffff;
      	for(int i=pre[2*n+1];bian[i].from!=4*n;i=pre[bian[i].from])
      	  {
      	  	 if(bian[i].liu<flow) flow=bian[i].liu;
		  }
      	for(int i=pre[2*n+1];bian[i].from!=4*n;i=pre[bian[i].from])
      	  {
      	  	  bian[i].liu-=flow;
      	  	  bian[i+1].liu+=flow;
		      zcost+=flow*bian[i].cost;   
		  }	    
	    zflow+=flow; 
	  }
	
	 return zcost; 
}

int main()
{
  // freopen("lx.in","r",stdin);
 //  freopen("lx.out","w",stdout);
   int i,j,k;
   
   init();
   int ans=flow_();
   cout<<ans;
   //cout<<zflow<<" ";
  // cout<<size;
   return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值