zzuli_acm_oj 1851 KILL 小模拟

57 篇文章 1 订阅
12 篇文章 0 订阅

有点小坑的模拟题,先解释下题意:

三国杀的简化版本,牌型有杀,闪,桃,万箭齐发,南蛮入侵,决斗

玩家是JS和DZ,JS行动一个回合,如果JS可以打死DZ,那么JS胜;否则DZ胜


题中解释的是:

杀只能用一次,必须响应,那么我们可以采取如下的贪心策略:

我们的目标是尽可能让DZ去死,那么就要集中火力打掉他的闪和杀(他的万箭齐发,南蛮入侵,决斗是没有用的),他的桃子可以直接计算到血量上限上去


跟DZ的闪有关的牌:

杀(只能用一次),万箭齐发(多次)

所以,我们直接把所有的万箭齐发全部用掉,尽可能的消耗DZ的闪(没有闪就掉血)

杀这张牌呢,要用贪心的思想考虑:如果DZ没有闪了,那么我们需要用这张杀(因为马上可以让他掉血,留着这张杀可能在决斗中有用,也可能没用,所以先用掉更优)


跟DZ的杀有关的牌:

决斗(多次),南蛮(多次),杀(在决斗中使用)

玩过三国杀的朋友,应该会知道又卖血这个功能的吧!比如如下这个数据:

5 2
J J J J J
K K

这个数据是JS赢的,因为先手在保证自己不被对手斗死的情况下,可以一直出决斗来浪费DZ的杀,进而可以用决斗或者南蛮入侵解决!

所以,我们在保证JS不死的前提下,一直决斗

注意决斗的规则:当JS的杀的数量不小于DZ的杀的数量时,DZ掉一血,消耗的杀的数量相等;否则,JS掉一血,DZ比JS多用一张杀

因为题中描述说有杀必须响应,所以至少把其中一个玩家的杀打光为止


接着把所有的南蛮入侵放掉,继续消耗杀(因为有可能DZ还有杀,再决斗自己就死了,所以先南蛮消耗杀,留着决斗)

最后,再把所有的决斗放掉(为什么这个时候不用保证自己不被对手斗死了呢?)

因为胜负条件:只要JS没把DZ打死,那么DZ胜;所以我们可以直接使用光所有的决斗,要么把JS打死了,要么把DZ打死了,要么数量不够



所以贪心策略:

先万箭齐发,再杀(在DZ没闪的情况),保证JS不死尽可能决斗,所有的南蛮入侵,用光决斗


代码如下:

#include<bits/stdc++.h>
using namespace std;

struct People{
    int K,S,N,W,J,Cnt;
}A,B;
char in[10];
int T,n,m;

void Add(People &X,char choose){
    if (choose=='K') X.K++;
    else if (choose=='S') X.S++;
    else if (choose=='N') X.N++;
    else if (choose=='W') X.W++;
    else if (choose=='J') X.J++;
    else if (choose=='T') X.Cnt++;
}

void Clear(People &X){
    X.K = X.S = X.N = X.W = X.J = X.Cnt = 0;
}

void Print(People X){
	printf("K:%d S:%d N:%d W:%d J:%d Cnt:%d\n",X.K,X.S,X.N,X.W,X.J,X.Cnt);
}

int main(){
    //freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        Clear(A);Clear(B);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%s",in);
            Add(A,in[0]);
        }
        for(int i=1;i<=m;i++){
            scanf("%s",in);
            Add(B,in[0]);
        }
        A.Cnt+=3;
        B.Cnt+=3;
        //所有的W用完
        if (A.W > 0){
            if (A.W >= B.S){
                B.Cnt = B.Cnt - (A.W - B.S);
                B.S = 0;
            }
            else{
                B.S = B.S - A.W;
            }
        }
        if (A.K > 0 && B.S == 0){
            B.Cnt--;
            A.K--;
        }
        //然后使用J
        while (A.J > 0 && A.Cnt > 1){
            if (A.K >= B.K){
                A.K -= B.K;
                B.K = 0;
                B.Cnt--;
            }
            else{
                B.K -= (A.K+1);
                A.K = 0;
                A.Cnt--;
            }
            A.J--;
        }
        if (A.N > 0){
            if (A.N >= B.K){
                B.Cnt = B.Cnt - (A.N - B.K);
                B.K = 0;
            }
            else{
                B.K = B.K - A.N;
            }
        }
        while (A.J > 0 && A.Cnt > 0){
            if (A.K >= B.K){
                A.K -= B.K;
                B.K = 0;
                B.Cnt--;
            }
            else{
                B.K -= (A.K+1);
                A.K = 0;
                A.Cnt--;
            }
            A.J--;
        }
        if (B.Cnt <= 0) puts("JS");
        else puts("DZ");
    }
    return 0;
}
//zzuli_1851

附几个Hack数据:

6 3
J J J N N N
K K K

6 3
J J J J J N
K K K

6 3
J J J N K W
K K S

4 2
J N N K
K S

6 4
J K K K N N
K K K K

6 3
J K K K N N
K K K

8 3
J J K K K K N N
K K K K

5 2
J J J N K
K K


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值