zoukankan      html  css  js  c++  java
  • 【BZOJ】【3442】学习小组

    网络流/费用流


      orz zyf

      裸的费用流,根据题目描述即可建出如下的图:

      S->i 费用表示每有一个加入第 i 个小组的学生,需要花的钱,由于是跟流量(人数)的二次方相关,所以要拆边……然后每个人的报名费直接用支出减去即可(也就是每条边的费用都减去一个常量)

      i->j+m 根据矩阵连边……如果第 j 个学生能报名第 i 个小组即连一条边,费用为0。

      j+m->T 容量为k,费用为0,表示每个人最多报k个小组。

      但是这题很坑啊!限制条件是参与学生尽量多,也就是说在一定会亏的时候每人最多只报一个小组……刚刚的建图,最小费用最大流行不通了!

      我们想想,如果一个人报名了会使得总支出减少,那他肯定要报名某一个小组,如果不能减少的话……就让这个改变量为0好了!

      所以我们对于每个人 j ,连边S->j+m (k-1,0)表示这个人最多可以有k-1个报名机会直接放弃掉!(因为要让参与人数尽量多啊……所以不能是k)

      1 /**************************************************************
      2     Problem: 3442
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:1560 ms
      7     Memory:3624 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 3442
     11 #include<vector>
     12 #include<cstdio>
     13 #include<cstring>
     14 #include<cstdlib>
     15 #include<iostream>
     16 #include<algorithm>
     17 #define rep(i,n) for(int i=0;i<n;++i)
     18 #define F(i,j,n) for(int i=j;i<=n;++i)
     19 #define D(i,j,n) for(int i=j;i>=n;--i)
     20 #define pb push_back
     21 using namespace std;
     22 inline int getint(){
     23     int v=0,sign=1; char ch=getchar();
     24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     26     return v*sign;
     27 }
     28 const int N=410,M=100000,INF=~0u>>2;
     29 typedef long long LL;
     30 /******************tamplate*********************/
     31 int n,m,k,ans,tmp,num,c[N];
     32 struct edge{int from,to,v,c;};
     33 struct Net{
     34     edge E[M];
     35     int head[N],next[M],cnt;
     36     void ins(int x,int y,int z,int c){
     37         E[++cnt]=(edge){x,y,z,c};
     38         next[cnt]=head[x]; head[x]=cnt;
     39     }
     40     void add(int x,int y,int z,int c){
     41         ins(x,y,z,c); ins(y,x,0,-c);
     42     }
     43     int from[N],Q[M],d[N],S,T,ed;
     44     bool inq[N],sign;
     45     bool spfa(){
     46         int l=0,r=-1;
     47         F(i,1,T) d[i]=INF;
     48         d[S]=0; Q[++r]=S; inq[S]=1;
     49         while(l<=r){
     50             int x=Q[l++];
     51             inq[x]=0;
     52             for(int i=head[x];i;i=next[i])
     53                 if(E[i].v>0 && d[x]+E[i].c<d[E[i].to]){
     54                     d[E[i].to]=d[x]+E[i].c;
     55                     from[E[i].to]=i;
     56                     if (!inq[E[i].to]){
     57                         Q[++r]=E[i].to;
     58                         inq[E[i].to]=1;
     59                     }
     60                 }
     61         }
     62         return d[T]!=INF;
     63     }
     64     void mcf(){
     65         int x=INF;
     66         for(int i=from[T];i;i=from[E[i].from])
     67             x=min(x,E[i].v);
     68         for(int i=from[T];i;i=from[E[i].from]){
     69             E[i].v-=x;
     70             E[i^1].v+=x;
     71         }
     72         ans+=x*d[T];
     73     }
     74     void init(){
     75         n=getint(); m=getint(); k=getint(); cnt=1;
     76         S=0; T=n+m+1; num=sign=0; tmp=-INF;
     77         F(i,1,m) c[i]=getint();
     78         int x;
     79         F(i,1,m){
     80             x=getint();
     81             F(j,1,n) add(S,i,1,c[i]*(j*2-1)-x);
     82         }
     83         char s[120];
     84         F(i,1,n) {
     85             scanf("%s",s+1);
     86             F(j,1,m){
     87                 x=s[j]-'0';
     88                 if (x) add(j,i+m,1,0);
     89             }
     90         }
     91         F(i,1,n) add(S,i+m,k-1,0),add(i+m,T,k,0);
     92         while(spfa()) mcf();
     93         printf("%d
    ",ans);
     94     }
     95 }G1;
     96  
     97 int main(){
     98 #ifndef ONLINE_JUDGE
     99     freopen("3442.in","r",stdin);
    100     freopen("3442.out","w",stdout);
    101 #endif
    102     G1.init();
    103     return 0;
    104 }
    View Code

    3442: 学习小组

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 176  Solved: 73
    [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

    [Submit][Status][Discuss]
  • 相关阅读:
    分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结
    动态规划 BZOJ1925 地精部落
    线性DP SPOJ Mobile Service
    线性DP codevs2185 最长公共上升子序列
    数位DP POJ3208 Apocalypse Someday
    线性DP POJ3666 Making the Grade
    杨氏矩阵 线性DP? POJ2279 Mr.Young's Picture Permutations
    tarjan强连通分量 洛谷P1262 间谍网络
    树链剖分 BZOJ3589 动态树
    二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
  • 原文地址:https://www.cnblogs.com/Tunix/p/4354843.html
Copyright © 2011-2022 走看看