Magic Potion(Gym-101981I)

Problem Description

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.

Sample Input

sample input 1

3 5 2
4 1 2 3 5
2 2 5
2 1 2

sample input 2

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

Sample Output

sample output 1

4

sample output 2

7

题意:有 n 个人,m 个怪兽,k 瓶药水,现在依次给出每个人可以杀的怪物的数量 t 以及怪物的编号,每个人只能杀他能杀的一个怪物,但可以领取一瓶药水复活再杀一个,问最多能杀死的怪物

思路:最大流

将 n 个人和 m 个怪兽视为一个点,将 n 个人编号编为从 1~n,m 个怪兽编号从 n+1~n+m,设一个虚拟节点 n+m+1 用于限制 k 瓶药水,设超级源点为 0 和超级汇点为 n+m+2

根据题意,将超级源点 0 向虚拟节点 n+m+1 连边,容量为 k;将 n 个人向其能杀死的 t 个怪物连边,容量为 1;将虚拟节点 n+m+1 向 n 个人连边,容量为 1;将每个怪物向超级汇点 n+m+2 连边,容量为 1

建好图后,跑 Dinic 即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
const int MOD = 1E9+7;
const int N = 1000+5;
const int dx[] = {0,0,-1,1,-1,-1,1,1};
const int dy[] = {-1,1,0,0,-1,1,-1,1};
using namespace std;

struct Edge {
    int from,to;
    int cap,flow;
    Edge() {}
    Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow) {}

};
int n,m;             //结点数,边数(含反向弧)
int S,T;             //源点、汇点
vector<Edge> edges;  //边表,edges[e]和edges[e^1]互为反向弧
vector<int> G[N];    //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[N];         //BFS使用,标记一个节点是否被遍历过
int dis[N];          //dis[i]表从起点s到i点的距离(层次)
int cur[N];          //cur[i]表当前正访问i节点的第cur[i]条弧
void addEdge(int from,int to,int cap) {
    edges.push_back( Edge(from,to,cap,0) );
    edges.push_back( Edge(to,from,0,0) );
    int m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
bool BFS() { //构建层次网络
    memset(vis,0,sizeof(vis));
    dis[S]=0;
    vis[S]=true;

    queue<int> Q;//用来保存节点编号
    Q.push(S);
    while(!Q.empty()) {
        int x=Q.front();
        Q.pop();
        for(int y=0; y<G[x].size(); y++) {
            Edge& e=edges[G[x][y]];
            if(!vis[e.to] && e.cap>e.flow) {
                vis[e.to]=true;
                dis[e.to]=dis[x]+1;
                Q.push(e.to);
            }
        }
    }
    return vis[T];
}

int DFS(int x,int cp) { //cp表示从s到x目前为止所有弧的最小残量
    if(x==T || cp==0)
        return cp;

    int flow=0,newFlow;//flow用来记录从x到t的最小残量
    for(int &y=cur[x]; y<G[x].size(); y++) {
        Edge &e=edges[G[x][y]];
        if(dis[x]+1==dis[e.to]) {
            int minn=min(cp,e.cap-e.flow);
            newFlow=DFS(e.to,minn);
            if(newFlow>0) {
                e.flow+=newFlow;
                edges[G[x][y]^1].flow-=newFlow;
                flow+=newFlow;
                cp-=newFlow;

                if(cp==0)
                    break;
            }
        }
    }
    return flow;
}
int Dinic() {
    int flow=0;
    while(BFS()) {
        memset(cur,0,sizeof(cur));
        flow+=DFS(S,INF);
    }
    return flow;
}

int main() {
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);

    addEdge(0,n+m+1,k);
    for(int i=1;i<=n;i++){
        addEdge(0,i,1);

        int t;
        scanf("%d",&t);
        while(t--){
            int x;
            scanf("%d",&x);
            addEdge(i,n+x,1);
        }

        addEdge(n+m+1,i,1);
    }
    for(int i=1;i<=m;i++)
        addEdge(n+i,n+m+2,1);

    S=0,T=n+m+2;
    printf("%d\n",Dinic());
}
posted @   老程序员111  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示