• Gym101981I Magic Potion(最大流)


    Problem I. Magic Potion

    There are n heroes and m monsters living in an island. The monsters became very vicious these days, so the heroes decided to diminish the monsters in the island. However, the i-th hero can only kill one monster belonging to the set Mi. Joe, the strategist, has k bottles of magic potion, each of which can buff one hero’s power and let him be able to kill one more monster. Since the potion is very powerful, a hero can only take at most one bottle of potion. Please help Joe find out the maximum number of monsters that can be killed by the heroes if he uses the optimal strategy.

    Input

      The first line contains three integers n, m, k (1 ≤ n, m, k ≤ 500) — the number of heroes, the number of monsters and the number of bottles of potion. Each of the next n lines contains one integer ti, the size of Mi, and the following ti integers Mi,j (1 ≤ j ≤ ti), the indices (1-based) of monsters that can be killed by the i-th hero (1 ≤ ti ≤ m, 1 ≤ Mi,j ≤ m).

    Output

       Print the maximum number of monsters that can be killed by the heroes.

    Examples

    standard input

    3 5 2

    4 1 2 3 5

    2 2 5

    2 1 2

    standard output

    4

     

    standard input

    5 10 2

    2 3 10

    5 1 3 4 6 10

    5 3 4 6 8 9

    3 1 9 10

    5 1 3 6 7 10

    standard output

    7

     

    题目大意


    给定n个英雄,m只怪兽,k瓶药。每个英雄只能杀一只怪,一个英雄磕了药后能够多杀一只,但一个英雄至多只能磕一次药。已知每个英雄能够杀死哪些怪兽,问最多杀几只怪。

     

    解题思路


    添加源点和两个中间结点,编号分别为1,2,3。再添加n个结点表示英雄,编号为4~n+3。再添加m个结点表示怪兽,编号为n+3+1~n+m+3。最后添加汇点,编号为n+m+4。

    连接源点和两个中间结点,容量分别为n和k。将每个英雄和两个中间节点连接,容量为1。将每个英雄和他能够消灭的怪兽连接,容量为1。最后将每个怪兽和汇点连接,容量为1。

    从源点到汇点跑最大流,结果即为最终的数量。

    PS:还有其他解法,如跑一遍容量为1的最大流后,在跑一遍容量为2的最大流,再分类讨论结果 。

     

    AC代码


      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int MAXN = 5e6+2333;  //X 集合中的顶点数上限
      4 const int MAXM = 5e6+2333;  // 总的边数上限
      5 const int INF = 0x3f3f3f3f;
      6 int head[MAXN],tot;
      7 int S,T;  // S 是源点,T 是汇点
      8 int d[MAXN];  // 存储每个顶点的层次
      9  10 struct Edge{
     11     int v,c,nxt;
     12     // v 是指边的另一个顶点,c 表示容量
     13 }e[MAXM];
     14  15 void init(){
     16     memset(head,-1,sizeof(head));
     17     tot=0;
     18 }
     19  20 void addedge(int u,int v,int c){
     21     // 插入一条从 u 连向 v,容量为 c 的弧
     22     e[tot].v=v;e[tot].c=c;
     23     e[tot].nxt=head[u];
     24     head[u]=tot++;
     25     
     26     e[tot].v=u;e[tot].c=0;
     27     e[tot].nxt=head[v];
     28     head[v]=tot++;
     29 }
     30  31 bool bfs(){
     32     // bfs构建层次图G_L
     33     memset(d,-1,sizeof(d));
     34     queue<int> q;
     35     q.push(S);
     36     d[S]=1;
     37     while(!q.empty()){
     38         int u=q.front();
     39         q.pop();
     40         for(int i=head[u];i!=-1;i=e[i].nxt){
     41             int v=e[i].v;
     42             if(e[i].c>0&&d[v]==-1){
     43                 q.push(v);
     44                 d[v]=d[u]+1;
     45             }
     46         }
     47     }
     48     return (d[T]!=-1);
     49 }
     50  51 int dfs(int u,int flow){
     52     // dfs在层次图G_L中寻找增广路径
     53     // flow 表示当前搜索分支的流量上限
     54     if(u==T){
     55         return flow;
     56     }
     57     int res=0;
     58     for(int i=head[u];i!=-1;i=e[i].nxt){
     59         int v=e[i].v;
     60         if(e[i].c>0&&d[u]+1==d[v]){
     61             int tmp=dfs(v,min(flow,e[i].c));
     62             // 递归计算顶点 v,用 c(u, v) 来更新当前流量上限
     63             flow-=tmp;
     64             e[i].c-=tmp;
     65             res+=tmp;
     66             e[i^1].c+=tmp;  // 修改反向弧的容量
     67             if(flow==0){  // 流量达到上限,不必继续搜索了
     68                 break;
     69             }
     70         }
     71     }
     72     if(res==0){
     73         // 当前没有经过顶点 u 的可行流,不再搜索顶点 u
     74         d[u]=-1;
     75     }
     76     return res;
     77 }
     78  79 int maxflow(){  // 函数返回值就是最大流的结果
     80     int res=0;
     81     while(bfs()){
     82         res+=dfs(S,INF);  // 初始流量上限为 INF
     83     }
     84     return res;
     85 }
     86  87 int main(){
     88     int m,n,k,mid1,mid2;
     89     while(~scanf("%d %d %d",&n,&m,&k)){
     90         init();
     91         S=1;T=n+m+4;mid1=2;mid2=3;
     92         int cnt,v;
     93         addedge(S,mid1,n);
     94         addedge(S,mid2,k);
     95         for(int i=1;i<=n;i++){
     96             addedge(mid1,i+3,1);
     97             addedge(mid2,i+3,1);
     98             scanf("%d",&cnt);
     99             for(int j=0;j<cnt;j++){
    100                 scanf("%d",&v);
    101                 addedge(i+3,n+v+3,1);
    102     }
    103     }
    104 for(int i=1;i<=m;i++)
    105 addedge(n+i+3,T,1);
    106 107         printf("%d\n",maxflow());
    108     }
    109     return 0;
    110 }
    View Code
     

     

  • 相关阅读:
    写了一个抓飞信包的小工具
    Drools.Net Bug?
    论坛系统分析比较
    在线个人财务管理服务推荐:财客在线网络账本
    多站点的google analytics的使用心得
    FeedSky更新出现很大延时
    愚人节,中华民族的伟大梦想实现了
    Community Server 2008.5 SP2发布啦
    [已上传流程图]在线服务器状态监控预警软件推荐:网站保姆
    五一公司搬家记
  • 原文地址:https://www.cnblogs.com/zengzk/p/10333975.html
Copyright © 2020-2023  润新知