zoukankan      html  css  js  c++  java
  • 【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
    " , mincost());
    	return 0;
    }

     

  • 相关阅读:
    redis 持久化
    Hyper-V虚拟机Redhat添加网卡找不到网卡配置文件解决方法
    java 查看ssl log
    iptables配置https防火墙策略
    java 一致性哈希源码 转
    mysql主备配置方法
    hibernate 缓存配置
    Hibernate中文乱码
    HttpPost 中文编码问题 EntityBuilder
    apache 配置tomcat代理
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6809670.html
Copyright © 2011-2022 走看看