zoukankan      html  css  js  c++  java
  • bzoj3442 学习小组

    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
    ",ans);
    }
    


  • 相关阅读:
    视频高清直播RTMP视频推流组件EasyRTMP-IOS版如何使用wchar_t*类型参数?
    设计模式
    算法学习【第10篇】:算法之动态规划问题
    算法学习【第9篇】:算法之斐波那契数列
    算法学习【第8篇】:贪心算法找零问题
    算法学习【第7篇】:算法之迷宫问题
    算法学习【第6篇】:算法之数据结构
    算法学习【第5篇】:常用排序算法(*******)
    算法学习【第4篇】:算法之---堆的简单介绍
    算法学习【第3篇】:树和二叉树简介
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7223817.html
Copyright © 2011-2022 走看看