码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3442 学习小组

时间:2017-07-23 11:19:44      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:数字   正整数   div   getch   string   流量   inf   有一个   names   

3442: 学习小组

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 200  Solved: 87
[Submit][Status][Discuss]

Description

【背景】
坑校准备鼓舞学生參加学习小组。
【描写叙述】
    共同拥有n个学生,m个学习小组,每一个学生有一定的喜好,仅仅愿意參加当中的一些学习小组,可是校领导为学生考虑。规定一个学生最多參加k个学习小组。財务处的大叔就没那么好了,他想尽量多收钱。由于每一个学生參加学习小组都要交一定的手续费。不同的学习小组有不同的手续费。然而,事与愿违,校领导又决定对学习小组组织者进行奖励,若有a个学生參加第i个学习小组,那么给这个学习小组组织者奖励Ci*a^2元。

在參与学生(而不是每一个学习小组的人数总和)尽量多的情况下,求財务处最少要支出多少钱(若为负数。则输出负数)(支出=总奖励费-总手续费)。

Input

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

Output

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

Sample Input


3 3 1
1 2 3
3 2 1
111
111
111

Sample Output


-2
【例子解释】
參与学生最多为3,每一个学生參加一个学习小组,若有两个学生參加第一个学习小组,一个学生參加第二个学习小组(一定要有人參加第二个学习小组)。支出为-2,能够证明没有更优的方案了。
【数据范围与约定】
100%的数据,0<n≤100,0<m≤90,0<k≤m,0<Ci≤10。0<Fi≤100。

HINT

Source




最小费用最大流,因为费用和流量的平方成正比,所以要用到拆边法

这道题有一个坑,就是在參与同学尽可能多的情况下,也就是说每一个人都參加,但每一个人的k不一定要满流,我们能够从每一个人的节点向汇点连一条容量为k-1、费用为0的边。




#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
#define maxn 300
#define maxm 50000
#define inf 1000000000
using namespace std;
struct edge_type
{
	int from,to,next,v,c;
}e[maxm];
int n,m,k,s,t,cnt=1,ans=0;
int head[maxn],dis[maxn],p[maxn],c[maxn],f[maxn];
bool inq[maxn];
char ch;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v,int c)
{
	e[++cnt]=(edge_type){x,y,head[x],v,c};head[x]=cnt;
	e[++cnt]=(edge_type){y,x,head[y],0,-c};head[y]=cnt;
}
inline bool spfa()
{
	queue<int>q;
	memset(inq,false,sizeof(inq));
	F(i,1,t) dis[i]=inf;
	dis[s]=0;inq[s]=true;q.push(s);
	while(!q.empty())
	{
		int x=q.front();inq[x]=false;q.pop();
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (e[i].v&&dis[y]>dis[x]+e[i].c)
			{
				dis[y]=dis[x]+e[i].c;
				p[y]=i;
				if (!inq[y]){inq[y]=true;q.push(y);}
			}
		}
	}
	return dis[t]!=inf;
}
inline void mcf()
{
	while(spfa())
	{
		int tmp=inf;
		for(int i=p[t];i;i=p[e[i].from]) tmp=min(tmp,e[i].v);
		ans+=tmp*dis[t];
		for(int i=p[t];i;i=p[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}
	}
}
int main()
{
	n=read();m=read();k=read();
	F(i,1,m) c[i]=read();
	F(i,1,m) f[i]=read();
	F(i,1,n) F(j,1,m)
	{
		ch=getchar();while (ch<'0'||ch>'1') ch=getchar();
		if (ch=='1') add_edge(i,j+n,1,0);
	}
	s=n+m+1;t=s+1;
	F(i,1,n) add_edge(s,i,k,0),add_edge(i,t,k-1,0);
	F(i,1,m) F(j,1,n) add_edge(i+n,t,1,(2*j-1)*c[i]-f[i]);
	mcf();
	printf("%d\n",ans);
}


bzoj3442 学习小组

标签:数字   正整数   div   getch   string   流量   inf   有一个   names   

原文地址:http://www.cnblogs.com/mfmdaoyou/p/7223817.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!