【bzoj3442】学习小组 费用流

原文地址:http://www.cnblogs.com/GXZlegend/p/6809670.html



题目描述

【背景】

坑校准备鼓励学生参加学习小组。

【描述】

共有n个学生,m个学习小组,每个学生有一定的喜好,只愿意参加其中的一些学习小组,但是校领导为学生考虑,规定一个学生最多参加k个学习小组。财务处的大叔就没那么好了,他想尽量多收钱,因为每个学生参加学习小组都要交一定的手续费,不同的学习小组有不同的手续费。然而,事与愿违,校领导又决定对学习小组组织者进行奖励,若有a个学生参加第i个学习小组,那么给这个学习小组组织者奖励Ci*a^2元。在参与学生(而不是每个学习小组的人数总和)尽量多的情况下,求财务处最少要支出多少钱(若为负数,则输出负数)(支出=总奖励费-总手续费)。

输入

输入有若干行,第一行有三个用空格隔开的正整数n、m、k。接下来的一行有m个正整数,表示每个Ci。第三行有m个正整数,表示参加每个学习小组需要交的手续费Fi。再接下来有一个n行m列的矩阵,表若第i行j列的数字是1,则表示第i个学生愿意参加第j个学习小组,若为0,则为不愿意。

输出

输出只有一个整数,为最小的支出。

样例输入

3 3 1

1 2 3

3 2 1

111

111

111

样例输出

-2



题解

拆边+费用流

由于有Ci*a^2的存在,使得正常加边的费用流无法处理。我们可以加容量为1,费用为Ci*1、Ci*3、Ci*5、Ci*7、...的一堆边,这样在最小费用的前提下总花费满足题意。

每个学习小组向T连上述所说的边,S向每个学生连一条容量为k,费用为0的边,每个学生向其能参加的学习小组连一条容量为1,费用为Fi的边。

因为题目中描述“在参与学生(而不是每个学习小组的人数总和)尽量多的情况下”,指的是所有学生必须有流通过,但不必满流。

所以还要从每个学生向T连一条容量为k-1,费用为0的边,保证费用最小。

然后跑最小费用最大流即可。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
queue<int> q;
int f[110] , head[210] , to[100000] , val[100000] , cost[100000] , next[100000] , cnt = 1 , s , t , dis[210] , from[210] , pre[210];
char str[110];
void add(int x , int y , int v , int c)
{
	to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
	to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt;
}
bool spfa()
{
	int x , i;
	memset(dis , 0x3f , sizeof(dis));
	memset(from , -1 , sizeof(from));
	dis[s] = 0 , q.push(s);
	while(!q.empty())
	{
		x = q.front() , q.pop();
		for(i = head[x] ; i ; i = next[i])
			if(val[i] && dis[to[i]] > dis[x] + cost[i])
				dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]);
	}
	return ~from[t];
}
int mincost()
{
	int i , k , ans = 0;
	while(spfa())
	{
		k = 0x3f3f3f3f;
		for(i = t ; i != s ; i = from[i]) k = min(k , val[pre[i]]);
		ans += k * dis[t];
		for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k;
	}
	return ans;
}
int main()
{
	int n , m , k , i , j , x;
	scanf("%d%d%d" , &n , &m , &k);
	s = 0 , t = n + m + 1;
	for(i = 1 ; i <= m ; i ++ )
	{
		scanf("%d" , &x);
		for(j = 1 ; j <= n ; j ++ ) add(i + n , t , 1 , x * (2 * j - 1));
	}
	for(i = 1 ; i <= m ; i ++ ) scanf("%d" , &f[i]);
	for(i = 1 ; i <= n ; i ++ )
	{
		add(s , i , k , 0) , add(i , t , k - 1 , 0);
		scanf("%s" , str + 1);
		for(j = 1 ; j <= m ; j ++ )
			if(str[j] == ‘1‘)
				add(i , j + n , 1 , -f[j]);
	}
	printf("%d\n" , mincost());
	return 0;
}
时间: 2024-11-08 04:11:06

【bzoj3442】学习小组 费用流的相关文章

BZOJ 3442 学习小组 费用流

题目大意:给出学生的数目和学习小组的数目,学生参加小组需要交纳费用,每个小组会支出C[i]*cnt[i]^2.每个学生可以参加k个小组,问最多的学生参加时,最小支出费用. 思路:如果不算后面那个什么鬼的条件的话,见图十分显然. S->每个学生 f:k,c:0 每个学生->每个学习小组 f:1,c:-F[i] 每个学习小组->T f:1,c:1 * C[i],3 * C[i],5 * C[i],7 * C[i],...... 后面的条件其实是说,每个学生的k次机会不一定全用光,但是所有人都

bzoj3442学习小组

题意: 共有n个学生,m个学习小组,每个学生只愿意参加其中的一些学习小组,且一个学生最多参加k个学习小组.每个学生参加学习小组财务处都收一定的手续费,不同的学习小组有不同的手续费.若有a个学生参加第i个学习小组,财务处支付奖励Ci*a^2元.在参与学生(而不是每个学习小组的人数总和)尽量多的情况下,求财务处最少要支出多少钱. 题解: s连n个学生,流量为k,费用为0.每个学生向喜欢的小组的连边,流量为1,费用为手续费的相反数.每个小组向t连边,它的费用与流量的平方成正比的边,需要把它拆成k条流量

bzoj3442 学习小组

目前处于迷之TLE状态 3442: 学习小组 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 200  Solved: 87 Description [背景] 坑校准备鼓励学生参加学习小组. [描述] 共有n个学生,m个学习小组,每个学生有一定的喜好,只愿意参加其中的一些学习小组,但是校领导为学生考虑,规定一个学生最多参加k个学习小组.财务处的大叔就没那么好了,他想尽量多收钱,因为每个学生参加学习小组都要交一定的手续费,不同的学习小组有不同的手续费.

算法学习:费用流

[前置知识] 最大流 [问题描述] 给定一个图,图上的边每条边有流量,流量有费用, 求在流量为 F 时费用的最小值 [分析思路] 求费用最小,我们很容易想到求最短路径,我们只需要将费用看作代价然后求最短路不久能求出来最小费用了嘛 但是,问题来了 我们又如何能够在求最小费用的同时,满足流量最终为F的条件 在最大流中提到,每次增广都是在残余网络中通过询问 s 至 t 的残余网络进行增广 所以,我们每次在残余网络上求最短路就可以了 这里注意,残余网络中的反向边的费用应该时原边费用的相反数 这样在计算的

学习了ZKW费用流

所谓ZKW费用流,其实就是Dinic. 若干年前有一个人发明了最小增广路算法,每次用BFS找一条增广路,时间O(nm^2) 然后被DinicD飞了:我们为什么不可以在长度不变时多路增广呢?时间O(n^2m) 于是可以用到费用流里来:我们为什么不可以在s到t最短路不变时多路增广呢? 实现做法要从t逆向做SPFA,然后多路增广,具体可以见代码 #include<cstdio> #include<cctype> #include<queue> #include<cstr

费用流(bzoj 3130)

Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超过其最大流量且非负:(2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量:而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量.最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案. 上图表示了一

bzoj 3130 [Sdoi2013]费用流(二分,最大流)

Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超过其最大流量且非负:(2)除了源点S和汇点T之外,对于其余所有点,都满足该点总流入流量等于该点总流出流量:而S点的净流出流量等于T点的净流入流量,这个值也即该网络流方案的总运输量.最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案.   上图表示

【BZOJ】【3442】学习小组

网络流/费用流 orz zyf 裸的费用流,根据题目描述即可建出如下的图: S->i 费用表示每有一个加入第 i 个小组的学生,需要花的钱,由于是跟流量(人数)的二次方相关,所以要拆边……然后每个人的报名费直接用支出减去即可(也就是每条边的费用都减去一个常量) i->j+m 根据矩阵连边……如果第 j 个学生能报名第 i 个小组即连一条边,费用为0. j+m->T 容量为k,费用为0,表示每个人最多报k个小组. 但是这题很坑啊!限制条件是参与学生尽量多,也就是说在一定会亏的时候每人最多只

BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 505[Submit][Status][Discuss] Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超