• bzoj3442: 学习小组(费用流好题)


    3442: 学习小组

    题目:传送门 


    题解:

       超级好题啊大佬们的神题!建图肥肠灵性!感觉自己是星际玩家。。。

       首先呢st直接向每个人连边,容量为min(k,喜欢的小组个数),费用为0

       然后每个人再向ed连,因为题目要求人数尽量多,那么每个人都至少要去一个学习小组,那么容量就为min(k-1,喜欢的小组个数-1),费用为0(表示每个人最多能不选的小组)

       每个人还要向自己喜欢的小组连边,容量为1,费用就为-F[i](因为题目问的是最小的支出,那么F表示的是手续费,所以肯定为负)

       灵性的操作来了:

       每个小组当然是还要向ed连的。

       直接就把每个小组向ed连n条边,表示不同人数参加该小组时的花费

       容量为1,流量就要推导一下:

       对于有i-1个人参加了该小组j,那么多一个人的费用差就是:C[j]*i^2-C[j]*(i-1)^2

       化简之后就是:C[j]*(2*i-1);

        


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define inf 999999999
     7 using namespace std;
     8 struct node
     9 {
    10     int x,y,c,d,next,other;
    11 }a[510000];int len,last[210];
    12 void ins(int x,int y,int c,int d)
    13 {
    14     int k1,k2;
    15     k1=++len;
    16     a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
    17     a[len].next=last[x];last[x]=len;
    18     
    19     k2=++len;
    20     a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
    21     a[len].next=last[y];last[y]=len;
    22     
    23     a[k1].other=k2;
    24     a[k2].other=k1;
    25 }
    26 int list[210],d[210],la[210],head,tail,st,ed,n,m,k,ans;
    27 bool v[210];
    28 bool spfa()
    29 {
    30     for(int i=1;i<=ed;i++)d[i]=inf;
    31     memset(v,false,sizeof(v));memset(la,0,sizeof(la));
    32     list[1]=st;d[st]=0;v[st]=true;head=1;tail=2;
    33     while(head!=tail)
    34     {
    35         int x=list[head];
    36         for(int k=last[x];k;k=a[k].next)
    37         {
    38             int y=a[k].y;
    39             if(a[k].c>0 && d[y]>d[x]+a[k].d)
    40             {
    41                 d[y]=d[x]+a[k].d;la[y]=k;
    42                 if(v[y]==false)
    43                 {
    44                     v[y]=true;
    45                     list[tail++]=y;
    46                     if(tail==ed+1)tail=1;
    47                 }
    48             }
    49         }
    50         head++;if(head==ed+1)head=1;
    51         v[x]=false;
    52     }
    53     if(d[ed]==inf)return false;
    54     return true;
    55 }
    56 int g_f()
    57 {
    58     int x,k,ans=0,f=inf;
    59     x=ed;while(x!=st){k=la[x];f=min(f,a[k].c);x=a[k].x;}
    60     x=ed;while(x!=st){k=la[x];a[k].c-=f;a[a[k].other].c+=f;x=a[k].x;}
    61     ans+=d[ed]*f;
    62     return ans;
    63 }
    64 int C[110],F[110],tot[110];
    65 char s[110];
    66 int main()
    67 {
    68     scanf("%d%d%d",&n,&m,&k);len=0;memset(last,0,sizeof(last));st=n+m+1,ed=st+1;
    69     for(int i=1;i<=m;i++)scanf("%d",&C[i]);for(int i=1;i<=m;i++)scanf("%d",&F[i]);
    70     for(int i=1;i<=n;i++)
    71     {
    72         scanf("%s",s+1);
    73         for(int j=1;j<=m;j++)if(s[j]=='1')ins(i,j+n,1,-F[j]),tot[i]++;
    74     }
    75     for(int i=1;i<=n;i++)ins(st,i,min(k,tot[i]),0),ins(i,ed,min(k-1,tot[i]-1),0);
    76     //C[j]*i^2-C[j]*(i-1)^2-->C[j]*(2*i-1)
    77     for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)ins(j+n,ed,1,C[j]*(2*i-1));
    78     ans=0;while(spfa())ans+=g_f();printf("%d
    ",ans);
    79     return 0;
    80 }    
  • 相关阅读:
    svn安装教程
    六、数组类的创建
    五、顺序存储线性表分析
    四、StaticList 和 DynamicList
    三、顺序存储结构的抽象实现
    二、线性表的顺序存储结构
    一、线性表的本质和操作
    专题五:局部变量、全局变量global、导入模块变量
    专题四:文件基础知识、字符编码
    专题3-2:列表基础知识:二维list排序、获取下标和处理txt文本实例
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8665766.html
Copyright © 2020-2023  润新知