【CF 724E】Goods transportation(最小割+DP)

【CF 724E】Goods transportation(最小割+DP)

题目大意:
n个工厂,每个工厂有生产量 p i p_i pi和最多销售量 s i s_i si。小编号工厂可以往大编号工厂运送货物,每对工厂最多传送c单位的货物。传送顺序随意。

问最终所有工厂最多销售量。

可以想到最大流。源点与每个工厂一条边,流量 p i p_i pi,每个工厂和汇点一条边,流量 s i s_i si。每个小工厂往每个大工厂有一条边,流量 c c c

跑完就可以得到结果了。

但是这题n 10^4,图是妥妥的建不出来。由长者们推出来的定理:最大流=最小割……

考虑将图分成两部分,集合A与集合B,A中有源点,B中有汇点,$A \cup B $=原图。

这样割就是 ∑ i ∈ A s i + ∑ j ∈ B p j + ∑ i < j , i ∈ A , j ∈ B c \sum\limits_{i \in A}s_i+\sum\limits_{j \in B}p_j+\sum\limits_{i<j,i \in A,j \in B}c iAsi+jBpj+i<j,iA,jBc

画出图来比较好看。大体就是:
这里写图片描述

被叉掉的就是一个割,也就是刚才那一长串。

求最小割的dp数组的定义也很绝。

d p [ i ] [ j ] dp[i][j] dp[i][j]表示图中存在1~i工厂,其中j个工厂与源点连通的最小割。

枚举工厂1~n,加点求min就行了。要注意的是直接n^2内存开不下,要做成滚动数组。

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 11234;

LL p[maxn],s[maxn];
LL dp[2][maxn];

int main()
{
	//fread("");
	//fwrite("");

	int n;
	LL c;

	scanf("%d%lld",&n,&c);

	for(int i = 1; i <= n; ++i) scanf("%lld",&p[i]);
	for(int i = 1; i <= n; ++i) scanf("%lld",&s[i]);

	int pre = 1;
	memset(dp,INF,sizeof(dp));

	dp[pre][0] = 0;

	for(int i = 1; i <= n; ++i)
	{
		pre ^= 1;

		for(int j = 0; j <= i; ++j)
		{
			dp[pre][j] = dp[pre^1][j]+p[i]+j*c;
			if(j) dp[pre][j] = min(dp[pre][j],dp[pre^1][j-1]+s[i]);
		}
	}

	LL ans = dp[pre][0];

	for(int i = 1; i <= n; ++i)
		ans = min(ans,dp[pre][i]);

	printf("%lld\n",ans);

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值