hdu 5383 Yu-Gi-Oh!(游戏王! + 费用流)

hdu 5383 Yu-Gi-Oh!

Problem Description
“Yu-Gi-Oh!”, also known as “Dueling Monsters”, is a popular trading card game which has nearly 20 years history. Next year, YGO will reach its 20th birthday.

Stilwell has n monsters on the desk, each monster has its leveli and ATKi. There are two kinds of monsters, Tuner monsters and Non-Tuner monsters.

Now, Stilwell plans to finish some “Synchro Summon”, and “Synchro Summon” is a kind of special summon following these rules (a little different from the standard YGO rules):

(1) A “Synchro Summon” needs two monsters as the material of this summon, and they must be one Tuner monster and one Non-Tuner monster.
In other words, we can cost one Tuner monster and one Non-Tuner monster to get a Synchro monster (“cost” means remove form the desk, “get” means put on to the desk).

(2) To simplify this problem, Synchro monsters are neither Tuner monsters nor Non-Tuner monsters.

(3) The level sum of two material must be equal to the level of Synchro monster we summon.
For example:
A Level 3 Tuner monster + A Level 2 Non-Tuner monster = A Level 5 Synchro Monster
A Level 2 Tuner monster + A Level 4 Non-Tuner monster = A Level 6 Synchro Monster
A Level 4 Tuner monster + A Level 4 Non-Tuner monster = A Level 8 Synchro Monster

(4) The material of some Synchro monster has some limits, the material must contain some specific monster.
For example:
A Level 5 Synchro Monster α requires A Level 3 Tuner monster α to be its material
A Level 6 Synchro Monster β requires A Level 4 Non-Tuner monster β to be its material
A Level 8 Synchro Monster γ requires A Level 4 Tuner monster γ + A Level 4 Non-Tuner monster γ to be its material
A Level 5 Synchro Monster φ doesn’t require any monsters to be its material
Then
A Level 3 Tuner monster α + A Level 2 Non-Tuner monster = A Level 5 Synchro Monster α
A Level 3 Tuner monster δ + A Level 2 Non-Tuner monster ≠ A Level 5 Synchro Monster α
A Level 2 Tuner monster + A Level 4 Non-Tuner monster β = A Level 6 Synchro Monster β
A Level 3 Tuner monster + A Level 3 Non-Tuner monster ζ ≠ A Level 6 Synchro Monster β
A Level 4 Tuner monster γ + A Level 4 Non-Tuner monster γ = A Level 8 Synchro Monster γ
A Level 4 Tuner monster σ + A Level 4 Non-Tuner monster γ ≠ A Level 8 Synchro Monster γ
A Level 4 Tuner monster γ + A Level 4 Non-Tuner monster ϕ ≠ A Level 8 Synchro Monster γ
A Level 3 Tuner monster + A Level 2 Non-Tuner monster = A Level 5 Synchro Monster φ
A Level 3 Tuner monster α + A Level 2 Non-Tuner monster = A Level 5 Synchro Monster φ

Stilwell has m kinds of Synchro Monster cards, the quantity of each Synchro Monster cards is infinity.

Now, given leveli and ATKi of every card on desk and every kind of Synchro Monster cards. Please finish some Synchro Summons (maybe zero) to maximum ∑ATKi of the cards on desk.

Input
The first line of the input contains a single number T, the number of test cases.

For each test case, the first line contains two integers n, m.

Next n lines, each line contains three integers tuneri, leveli, and ATKi, describe a monster on the desk. If this monster is a Tuner monster, then tuneri=1, else tuneri=0 for Non-Tuner monster.

Next m lines, each line contains integers levelj, ATKj, rj, and following rj integers are the required material of this Synchro Monster (the integers given are the identifier of the required material).
The input data guarantees that the required material list is available, two Tuner monsters or two Non-Tuner monsters won’t be required. If ri=2 the level sum of two required material will be equal to the level of Synchro Monster.

T≤10, n,m≤300, 1≤leveli≤12, 0≤ATKi≤5000, 0≤ri≤2

Output
T lines, find the maximum ∑ATKi after some Synchro Summons.

Sample Input

5
2 2
1 3 1300
0 2 900
5 2300 1 1
8 2500 0
2 1
1 3 1300
1 2 900
5 2300 1 1
3 1
1 3 1300
0 2 900
0 2 800
5 2300 1 1
3 1
1 1 233
0 1 233
0 1 200
2 466 2 1 2
6 3
1 3 1300
0 2 900
0 5 1350
1 4 1800
0 10 4000
0 10 1237
5 2300 1 1
8 3000 0
6 2800 0

Sample Output

2300
2200
3200
666
11037

题目大意:场上有n只怪兽,有m种同调召唤的方式。当两只怪兽的类型不同,并且这两只怪兽的等级相加之后等于新怪的等级,则这两只怪兽可以作为祭品同调召唤新的怪兽。现在要求求出,经过同调召唤后(可以不进行同调召唤),最大的场攻是多少。
解题思路:设置一个超级源点,连向所有类型为0的怪兽,容量为1,费用为0。设置一个超级汇点,使所有类型为1的怪兽连向它,容量为1,费用为0。然后将可以进行同调召唤的两只怪兽连起来,容量为1,费用为原本两只怪兽的攻击力之和减去同调召唤后新怪兽的攻击力。最后让一开始的场攻减去求出的最小费用,就是答案了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;

const int PO = 305;
const int INF = 0x3f3f3f3f;
const int N = 1010;
const int M = 100000;
typedef long long ll;
int n, m, cnt1, cnt2, s, t, sum;
int pre[N], inq[N]; 
int a[N], d[N], gra[N][N];
struct desk{ //de[i][j]记录类型i的怪兽中的第j只的信息
    int id, type, level, atk;
}de[2][PO];
struct REC{ //rec[i]记录场上的第i只怪兽的类别,以及在该类别的数组中的位置
    int f, id;
}rec[PO];

struct Edge{
    int from, to;
    int cap, flow;
    int cos;
};

vector<Edge> edges;
vector<int> G[M];

void init() {
    memset(gra, 0, sizeof(gra));
    cnt1 = cnt2 = 1;
    sum = 0;
    for (int i = 0; i <= n * n * 2; i++) G[i].clear();
    edges.clear();
}

void addEdge(int from, int to, int cap, int cos) {
    edges.push_back((Edge){from, to, cap, 0, cos});
    edges.push_back((Edge){to, from, 0, 0, -cos});
    int m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
}

int BF(int s, int t, int& flow, int& cost) {
    queue<int> Q;
    memset(inq, 0, sizeof(inq));
    memset(a, 0, sizeof(a));
    memset(pre, 0, sizeof(pre));
    for (int i = 0; i <= n + 2; i++) d[i] = INF;
    d[s] = 0;
    a[s] = INF;
    inq[s] = 1;
    pre[s] = 0;
    Q.push(s);
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for (int i = 0; i < G[u].size(); i++) {
            Edge &e = edges[G[u][i]];
            if (e.cap > e.flow && d[e.to] > d[u] + e.cos) {
                d[e.to] = d[u] + e.cos;
                a[e.to] = min(a[u], e.cap - e.flow);
                pre[e.to] = G[u][i];
                if (!inq[e.to]) {
                    inq[e.to] = 1;
                    Q.push(e.to);
                }
            }   
        }
    }
    if (d[t] >= 0) return 0; 
    flow += a[t];
    cost += d[t] * a[t];
    for (int u = t; u != s; u = edges[pre[u]].from) {
        edges[pre[u]].flow += a[t];
        edges[pre[u]^1].flow -= a[t];
    }
    return 1;
}

int MCMF(int s, int t, int& cost) {
    int flow = 0;
    cost = 0;       
    while (BF(s, t, flow, cost));    
    return cost;
}

void input() {
    scanf("%d %d", &n, &m);
    s = 0, t = n + 2;
    for (int i = 1; i <= n; i++) {
        int type, level, atk;
        scanf("%d %d %d", &type, &level, &atk);
        if (!type) { //按怪物类型存在不同数组
            rec[i].f = 0, rec[i].id = cnt1; 
            de[0][cnt1++] = (desk){i, type, level, atk};
            addEdge(s, i, 1, 0);
            sum += atk;
        } else {
            rec[i].f = 1, rec[i].id = cnt2;
            de[1][cnt2++] = (desk){i, type, level, atk};
            addEdge(i, t, 1, 0);
            sum += atk;
        }
    }
    int level1, level2;
    for (int i = 1; i <= m; i++) {
        //当两只不同类型的怪等级相加等于新怪的等级,则这两只不同类型的怪可以合成新的怪,新怪的攻击大于原本两只怪的攻击之和,这次合成才是有效的
        int level, atk, r;
        scanf("%d %d %d", &level, &atk, &r);    
        if (r == 2) {
            int a, b;
            scanf("%d %d", &a, &b);
            level1 = de[rec[a].f][rec[a].id].level;
            level2 = de[rec[b].f][rec[b].id].level;
            if (rec[a].f) swap(a, b);
            if (level1 + level2 == level) {
                gra[rec[a].id][rec[b].id] = max(gra[rec[a].id][rec[b].id], atk);
            }
        } else if (r == 1) {
            int a;
            scanf("%d", &a);
            if (!rec[a].f) {
                for (int j = 1; j < cnt2; j++) {
                    level1 = de[0][rec[a].id].level;
                    level2 = de[1][j].level;
                    if (level1 + level2 == level) {
                        gra[rec[a].id][j] = max(gra[rec[a].id][j], atk);
                    }
                }    
            } else {
                for (int j = 1; j < cnt1; j++) {
                    level1 = de[1][rec[a].id].level;
                    level2 = de[0][j].level;
                    if (level1 + level2 == level) {
                        gra[j][rec[a].id] = max(gra[j][rec[a].id], atk);
                    }
                }    
            }
        } else {
            for (int j = 1; j < cnt1; j++) {
                for (int k = 1; k < cnt2; k++)    {
                    level1 = de[0][j].level;
                    level2 = de[1][k].level;
                    if (level1 + level2 == level) {
                        gra[j][k] = max(gra[j][k], atk);
                    }
                }
            }
        }
    }
    for (int i = 1; i < cnt1; i++) {
        for (int j = 1; j < cnt2; j++) {
            int atk1 = de[0][i].atk;
            int atk2 = de[1][j].atk;
            if (gra[i][j] > 0 && gra[i][j] > atk1 + atk2) {
                addEdge(de[0][i].id, de[1][j].id, 1, atk1 + atk2 - gra[i][j]);    
            }    
        }    
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        init();
        input();    
        int cost;
        printf("%d\n", sum - MCMF(s, t, cost));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值