• 拍照


    题目描述

    小B有n个下属,现小B要带着一些下属让别人拍照。

    有m个人,每个人都愿意付给小B一定钱让n个人中的一些人进行合影。如果这一些人没带齐那么就不能拍照,小B也不会得到钱。

    注意:带下属不是白带的!!!对于每个下属,如果他带了那么小B需要给他一些钱,保证当他拍照时配合。

    请问,小B的净收益最多是多少。

    输入输出格式

    输入格式:

    第1行有2个正整数m和n(0<m,n<=100)。接下来的m行,每行是一个要求拍照的人的有关数据。第一个数是他同意支付该合影的费用;接着是该合影需要的若干下属的编号,以一个0作为行的结束标记。最后一行的n个数是带每个下属的费用。

    输出格式:

    一个数,表示最大收益。小B可以一个人也不带。

    输入输出样例

    输入样例#1:
    2 3
    10 1 2 0
    25 2 3 0
    5 6 7
    输出样例#1:
    17

    说明

    对于10%的数据每个人都要求让全部n个人合影

    对于30%的数据n<=15 m<=15

    另有10%的数据答案为0

    对于50%的数据n<=40 m<=40

    另有10%的数据每个人只愿意拍一个人

    对于100%的数据m,n<=100

    思路:最大权闭合子图

    m个请求与s连边,权值为方案价值;

    n个员工与t连边,权值为员工花费;

    方案与牵扯到的员工连边,权值为inf;

    然后跑最大流,总流量就是最优方案的总花费;

    然后,总收益=总价值-总花费。

    代码实现:

     1 #include<cstdio>
     2 #include<cstring>
     3 #define inf 1000000
     4 #define maxn 300
     5 #define maxm 300000
     6 int n,m,s,t,tw,tot;
     7 int a,b,c;
     8 int d[maxn],q[maxn],head,tail;
     9 int h[maxn],hs=1;
    10 struct edge{int s,n,w;}e[maxm];
    11 inline int min(int x,int y){return x<y?x:y;}
    12 void add(int q,int z,int w){
    13     e[++hs]=(edge){z,h[q],w},h[q]=hs;
    14     e[++hs]=(edge){q,h[z]},h[z]=hs;
    15 }
    16 void bfs(){
    17     memset(d,0,sizeof(d));
    18     head=tail=0;
    19     q[head++]=s,d[s]=1;
    20     while(head>tail){
    21         a=q[tail++];
    22         for(int i=h[a];i;i=e[i].n)
    23         if(!d[e[i].s]&&e[i].w){
    24             d[e[i].s]=d[a]+1;
    25             if(e[i].s==t) return;
    26             q[head++]=e[i].s;
    27         }
    28     }
    29 }
    30 int ap(int k,int w){
    31     if(k==t) return w;
    32     int uw=w;
    33     for(int i=h[k];i&&uw;i=e[i].n)
    34     if(e[i].w&&d[e[i].s]==d[k]+1){
    35         int nw=ap(e[i].s,min(uw,e[i].w));
    36         if(nw) e[i].w-=nw,e[i^1].w+=nw,uw-=nw;
    37         else d[e[i].s]=0;
    38     }
    39     return w-uw;
    40 }
    41 void Dinic(){while(bfs(),d[t]) tw+=ap(s,inf);}
    42 int main(){
    43     scanf("%d%d",&m,&n);
    44     s=0,t=n+m+1;
    45     for(int i=1;i<=m;i++){
    46         scanf("%d",&a);
    47         tot+=a;
    48         add(s,i,a);
    49         while(scanf("%d",&a)&&a) add(i,a+m,inf);
    50     }
    51     for(int i=1;i<=n;i++) scanf("%d",&a),add(i+m,t,a);
    52     Dinic();
    53     printf("%d
    ",tot-tw);
    54     return 0;
    55 }

    因为hs初值忘了赋一,挣扎了1h,我绝对要玩。

    本来想水水网络流,增加一下信心,没想到第一个题就坑了,搞了1h,才用土法子拿了80分。

    明明不是正解,还固执己见,看了人家的AC代码,还不想该。

    最后又惊扰了师傅他老人家,才知道是最大权闭合子图的裸题。

     1 #include<cstdio>
     2 #include<cstring>
     3 #define inf 100000000
     4 #define maxn 300
     5 #define maxm 300000
     6 int n,m,s,t,tw;
     7 int a,b,c;
     8 int f[maxn],l[maxn],map[maxn][maxn];
     9 int d[maxn],q[maxn],head,tail;
    10 int h[maxn],hs;
    11 struct edge{int s,n,w;}e[maxm];
    12 inline int min(int x,int y){return x<y?x:y;}
    13 void bfs(){
    14     memset(d,0,sizeof(d));
    15     head=tail=0;
    16     q[head++]=s,d[s]=1;
    17     while(head>tail){
    18         a=q[tail++];
    19         for(int i=h[a];i;i=e[i].n)
    20         if(!d[e[i].s]&&e[i].w){
    21             d[e[i].s]=d[a]+1;
    22             if(e[i].s==t) return;
    23             q[head++]=e[i].s;
    24         }
    25     }
    26 }
    27 int ap(int k,int w){
    28     if(k==t) return w;
    29     int uw=w;
    30     for(int i=h[k];i&&uw;i=e[i].n)
    31     if(e[i].w&&d[e[i].s]==d[k]+1){
    32         int nw=ap(e[i].s,min(uw,e[i].w));
    33         if(nw) e[i].w-=nw,e[i^1].w+=nw,uw-=nw;
    34         else d[e[i].s]=0;
    35     }
    36     return w-uw;
    37 }
    38 bool Dinic(){
    39     bfs();
    40     if(!d[t]) return false;
    41     tw+=ap(s,inf);
    42     return true;
    43 }
    44 int main(){
    45     scanf("%d%d",&m,&n);
    46     s=0,t=n+1;
    47     for(int i=1;i<=m;i++){
    48         while(scanf("%d",&map[i][l[i]])&&map[i][l[i]++]);
    49         map[i][l[i]-1]=t;
    50     }
    51     for(int i=1;i<=n;i++) scanf("%d",&f[i]);
    52     for(int i=1;i<=m;i++){
    53         b=s;
    54         for(int j=1;j<l[i]&&map[i][0];j++){
    55             a=b,b=map[i][j],c=map[i][0];
    56             e[++hs]=(edge){b,h[a],c},h[a]=hs;
    57             e[++hs]=(edge){a,h[b]},h[b]=hs;
    58             if(c>=f[b]) map[i][0]-=f[b],f[b]=0;
    59             else f[b]-=c,map[i][0]=0;
    60         }
    61     }
    62     while(Dinic());
    63     printf("%d
    ",tw);
    64     return 0;
    65 }
    问题代码(留作纪念)

    完成了可以看一下原版

    题目来源:洛谷

  • 相关阅读:
    买了一个 站立式办公 桌子。
    AutoCppHeader AutoHeader 自动根据CPP 或C文件 来生成头文件。
    cplusplus 库 在线管理; 类似于 python的 pip install 、nodejs 的npm模块
    var this.value 可在任意地方 声明 类成员变量。如果可以利用在C++ 那该有多好啊
    最近遇到了 timer1sec 定时调用的函数,出现了 时间久了,就不是每秒一次了,可能会慢的情况。如何解决呢?
    【我的愿景】每个程序员都应该学习编译原理,而每个人都应该学习 编程 和 设计。
    [已解决]下载chromium源码 download_from_google_storage 无法下载文件
    突发奇想-取缔宏定义,用另外一种语言来做C++的部分外层封装
    我讨厌Apple Safari浏览器的一些地方。不想用
    unix时间戳time_t与UTC时区的关系
  • 原文地址:https://www.cnblogs.com/J-william/p/6596496.html
Copyright © 2020-2023  润新知