hdu5579 2015区域赛上海赛区G.Game of Arrays

博弈论游戏算法解析

题意:给你三个数组A,B,C,三个数组长度相等,当中有一些位置可以进行(-1)操作,定义A+B=C为对于三个数组中的每个数都有a[i]+b[i]=c[i],先手想让A+B=C成立,后手不想让等式成立,如果当中某一时刻等式成立则先手胜,否则后手胜,问最后胜利者是谁;

首先在于如果要让A+B=C成立,那么每个位置都必须满足a[i]+b[i]=c[i],只要有任何一个地方不能满足,就可以直接输出后手赢。

对于每个位置,根据三个数是否能修改讨论,一共应当是8种情况,但可以等价化到6种(0+1=0优化成1+0=0,0+1=1优化为1+0=1);


然后这六种情况又会有四种结果:

1.固定状态,对应0+0=0的情况,如果a[i]+b[i]!=c[i]则返回0;

2.稳定状态,对于1+1=1以及(1+0=1且b[i]==0),也就是说减到最后可减的地方都变为0时等式依然成立,这种状态是稳定的;

3.脆弱状态,就是说在某一个时刻能够满足a[i]+b[i]=c[i],但再操作的话,就无法满足;

4.非法状态,直接返回0;

对于每个位置如果会到达脆弱状态,则记录步数weak[i],同时记录会到达脆弱状态的个数weakn;

如果会到达稳定状态,则记录到达稳定状态的步数的和stasum;


但是有一种情况需要特别照顾,就是上文稳定状态中提到的1+0=1,但b[i]!=0的情况。

1.a[i]+b[i]>c[i]+1,非法;

2.a[i]+b[i]==c[i]+1,也就是说必须一次操作就完成,所以这种状态在所有位置中只能最多出现一次,否则就return 0;

3.a[i]+b[i]<c[i],会达到脆弱状态。

具体看代码QAQ


#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<cctype>

#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<set>
#include<algorithm>
#include<stack>

//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
const int INF = 0x7fffffff;
typedef long long ll;
const double eps = 1e-8;
const double PI = 2 * cos(0.0);
const int MOD = 1000000007;

#define MAXN 101

int n;
int a[MAXN], ap[MAXN];
int b[MAXN], bp[MAXN];
int c[MAXN], cp[MAXN];
int weak[MAXN];

bool match()
{
    mem(weak, 0);
    int flag = 1;
    int weakn = 0;
    ll strsum = 0;
    for (int i = 1; i <= n; i++)
    {
        int tmp = abs(a[i] + b[i] - c[i]);
        if (!ap[i] && !bp[i] && !cp[i])
        {
            if (a[i] + b[i] != c[i]) return 0;
        }
        if (ap[i] && bp[i] && cp[i])
        {
            strsum += tmp;
        }
        else if (ap[i] && bp[i] && !cp[i])
        {
            if (a[i] + b[i] < c[i]) return 0;
            if (!c[i]) strsum += tmp;
            else weak[++weakn] = tmp;
        }
        else if (!ap[i] && !bp[i] && cp[i])
        {
            if (a[i] + b[i] > c[i]) return 0;
            if (!a[i] && !b[i]) strsum += tmp;
            else weak[++weakn] = tmp;
        }
        else if (ap[i] && !bp[i] && !cp[i])
        {
            if (a[i] + b[i] < c[i])return 0;
            if (b[i] == c[i])strsum += tmp;
            else weak[++weakn] = tmp;
        }
        else if (ap[i] && !bp[i] && cp[i])
        {
            if (!b[i])
            {
                strsum += tmp;
                continue;
            }
            if (b[i]>c[i]) return 0;
            if (a[i] + b[i] > c[i] + 1) return 0;
            if (a[i] + b[i] == c[i] + 1)
            {
                if (!flag) return 0;
                flag = 0;
            }
            tmp = c[i] - a[i] - b[i];
            weak[++weakn] = tmp;
        }
    }
    if (!weakn) return 1;
    else if (weakn == 1)
    {
        if (strsum <= weak[1] + 1) return 1;
    }
    else if (weakn == 2)
    {
        if (strsum == 0)
        {
            if (abs(weak[1] - weak[2]) == 1) return 1;
        }
        else if (strsum == 1)
        {
            if (abs(weak[1] - weak[2]) == 0) return 0;
        }
    }
    else
    {
        ll sum = strsum;
        for (int i = 1; i <= n; i++)
        {
            sum += abs(weak[i]);
            if (sum > 1) return 0;
        }
        return 1;
    }
    return 0;
}

int main()
{
    int T;
    cin >> T;
    for (int kase = 1; kase <= T; kase++)
    {
        cin >> n;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &ap[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &bp[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &cp[i]);

        for (int i = 1; i <= n; i++)
        {
            if (!a[i]) ap[i] = 0;
            if (!b[i]) bp[i] = 0;
            if (!c[i]) cp[i] = 0;
            if (!ap[i] && bp[i])
            {
                swap(a[i], b[i]);
                swap(ap[i], bp[i]);
            }
        }
        printf("Case #%d: %s\n", kase, match() ? "Tweek" : "Craig");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值