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());
}
好的,以下是制作背包的基本思路: 1. 创建一个背包界面,包含物品的图标、名称、数量等信息。 2. 创建一个物品类,用来存储每个物品的信息,包括编号、名称、图标、数量等信息。 3. 在游戏启动时读取text文件中的物品信息,将每个物品的信息存储到物品类中,并将物品类存储到一个数组中。 4. 点击背包界面中的物品图标时,根据物品编号在物品数组中查找对应的物品信息,并在背包界面中显示该物品的详细信息。 5. 可以在背包界面中拖拽物品图标进行交换位置,或者丢弃物品。 下面是一个示例代码,可以参考一下: ```csharp using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; // 物品类 public class Item { public int id; // 物品编号 public string name; // 物品名称 public Sprite icon; // 物品图标 public int count; // 物品数量 public int price; // 物品价格 public int hp; // 恢复生命值 public int mp; // 恢复魔法值 // 从text文件中读取物品信息 public static Item Load(string line) { string[] data = line.Split(','); Item item = new Item(); item.id = int.Parse(data[0]); item.name = data[1]; item.icon = Resources.Load<Sprite>(data[2]); item.count = int.Parse(data[3]); item.price = int.Parse(data[4]); item.hp = int.Parse(data[5]); item.mp = int.Parse(data[6]); return item; } } // 背包界面 public class Backpack : MonoBehaviour { public Image itemIcon; // 物品图标 public Text itemName; // 物品名称 public Text itemCount; // 物品数量 public Text itemPrice; // 物品价格 public Text itemHp; // 恢复生命值 public Text itemMp; // 恢复魔法值 public Transform content; // 背包物品容器 private List<Item> items = new List<Item>(); // 物品列表 // 游戏启动时加载物品信息 private void Start() { TextAsset asset = Resources.Load<TextAsset>("items"); string[] lines = asset.text.Split('\n'); foreach (string line in lines) { Item item = Item.Load(line); items.Add(item); } } // 点击物品图标时显示该物品的详细信息 public void OnItemClick(int id) { Item item = items.Find(x => x.id == id); itemIcon.sprite = item.icon; itemName.text = item.name; itemCount.text = "数量:" + item.count; itemPrice.text = "价格:" + item.price; itemHp.text = "恢复生命值:" + item.hp; itemMp.text = "恢复魔法值:" + item.mp; } // 向背包中添加物品 public void AddItem(int id, int count) { Item item = items.Find(x => x.id == id); if (item != null) { item.count += count; UpdateItem(item); } } // 从背包中移除物品 public void RemoveItem(int id, int count) { Item item = items.Find(x => x.id == id); if (item != null) { item.count -= count; UpdateItem(item); } } // 更新物品信息 private void UpdateItem(Item item) { foreach (Transform child in content) { ItemSlot slot = child.GetComponent<ItemSlot>(); if (slot.itemId == item.id) { slot.UpdateItem(item); break; } } } } // 背包中的物品槽 public class ItemSlot : MonoBehaviour { public Image itemIcon; // 物品图标 public Text itemCount; // 物品数量 public int itemId; // 物品编号 public int itemAmount; // 物品数量 // 更新物品信息 public void UpdateItem(Item item) { itemId = item.id; itemAmount = item.count; itemIcon.sprite = item.icon; itemCount.text = item.count.ToString(); } } ``` 使用方法: 1. 创建一个UI界面,添加上述代码中的Backpack组件。 2. 创建一个TextAsset资源,命名为items,并将物品信息按照示例格式填入。 3. 在UI界面中添加一个ItemSlot预制体,用来显示每个物品的图标和数量。 4. 在UI界面中添加一个拖拽组件,用来实现物品的拖拽和交换。 5. 在代码中调用Backpack组件的AddItem和RemoveItem方法,可以向背包中添加或移除物品。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值