ACM-ICPC 2018 徐州网络赛 B. BE, GE or NE (博弈dp)

版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82625662

In a world where ordinary people cannot reach, a boy named "Koutarou" and a girl named "Sena" are playing a video game. The game system of this video game is quite unique: in the process of playing this game, you need to constantly face the choice, each time you choose the game will provide 1-31−3 options, the player can only choose one of them. Each option has an effect on a "score" parameter in the game. Some options will increase the score, some options will reduce the score, and some options will change the score to a value multiplied by -1−1 .

That is, if there are three options in a selection, the score will be increased by 11, decreased by 11, or multiplied by -1−1. The score before the selection is 88. Then selecting option 11 will make the score become 99, and selecting option 22 will make the score 77 and select option 33 to make the score -8−8. Note that the score has an upper limit of 100100 and a lower limit of -100−100. If the score is 9999 at this time, an option that makes the score +2+2 is selected. After that, the score will change to 100100 and vice versa .

After all the choices have been made, the score will affect the ending of the game. If the score is greater than or equal to a certain value kk, it will enter a good ending; if it is less than or equal to a certain value ll, it will enter the bad ending; if both conditions are not satisfied, it will enter the normal ending. Now, Koutarou and Sena want to play the good endings and the bad endings respectively. They refused to give up each other and finally decided to use the "one person to make a choice" way to play the game, Koutarou first choose. Now assume that they all know the initial score, the impact of each option, and the kk, ll values, and decide to choose in the way that works best for them. (That is, they will try their best to play the ending they want. If it's impossible, they would rather normal ending than the ending their rival wants.)

Koutarou and Sena are playing very happy, but I believe you have seen through the final ending. Now give you the initial score, the kk value, the ll value, and the effect of each option on the score. Can you answer the final ending of the game?

Input

The first line contains four integers n,m,k,ln,m,k,l(1\le n \le 10001≤n≤1000, -100 \le m \le 100−100≤m≤100 , -100 \le l < k \le 100−100≤l<k≤100), represents the number of choices, the initial score, the minimum score required to enter a good ending, and the highest score required to enter a bad ending, respectively.

Each of the next nn lines contains three integers a,b,ca,b,c(a\ge 0a≥0 , b\ge0b≥0 ,c=0c=0 or c=1c=1),indicates the options that appear in this selection,in which a=0a=0 means there is no option to increase the score in this selection, a>0a>0 means there is an option in this selection to increase the score by aa ; b=0b=0 means there is no option to decrease the score in this selection, b>0b>0 means there is an option in this selection to decrease the score by bb; c=0c=0 means there is no option to multiply the score by -1−1 in this selection , c=1c=1 means there is exactly an option in this selection to multiply the score by -1−1. It is guaranteed that a,b,ca,b,c are not equal to 00 at the same time.

Output

One line contains the final ending of the game. If it will enter a good ending,print "Good Ending"(without quotes); if it will enter a bad ending,print "Bad Ending"(without quotes);otherwise print "Normal Ending"(without quotes).

样例输入1

3 -8 5 -5
3 1 1
2 0 1
0 2 1

样例输出1

Good Ending

样例输入2

3 0 10 3
0 0 1
0 10 1
0 2 1

样例输出2

Bad Ending

题目大意:两个人轮流对一个数m进行操作,总共有三种操作:加a,减b,取相反数。每轮操作的a,b不尽相同,而且三种操作不一定都能进行。第一个人希望最后得到的数>=k,第二个人则希望这个数<=l。如果最后得到的数>=k,则输出"Good Ending";如果<=l,则输出"Bad Ending";否则输出"Normal Ending"。若某次操作后得到的数>100或<-100,则将其变为100或-100,即需要将m控制在[-100,100]之内。

解法:由于总状态数较少,可以考虑采用dp的方法。设d[i][j]表示在进行第i个操作并且m的值为j的局面的dp值,不妨将"第一个人胜利"的局面的dp值设为1,将"第二个人胜利"的局面的dp值设为-1,将平局的dp值设为0。如果后继状态的dp值中有-1,则当前状态的dp值为1,否则如果有0,则当前状态的dp值为0,再否则就为-1。

状态转移式为:dp[i][j]->dp[i+1][j+a],dp[i+1][j-b],dp[i+1][-j]

最后再判断下进行完所有操作后,当前操作的那个人是谁,分情况做一下边界处理就可以了。

注意要控制m的值在给定的范围内,而且记录在数组中的m值至少要加上100,因为数组的下标不能为负。

AC代码:

#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
const int INF=0x3f3f3f3f;
int n,m,k,l;
int a[N],b[N],c[N];
int d[N][200+10];

int dp(int u,int x)
{
    x-=100;
    if(x<-100)x=-100;
    if(x>100)x=100;
    if(d[u][x+100]!=INF)return d[u][x+100];
    if(u==n)
    {
        if(!(u&1))
        {
            if(x>=k)return 1;
            if(x<=l)return -1;
            return 0;
        }
        else
        {
            if(x>=k)return -1;
            if(x<=l)return 1;
            return 0;
        }
    }
    int flag[]= {a[u]?dp(u+1,x+a[u]+100):1,b[u]?dp(u+1,x-b[u]+100):1,c[u]?dp(u+1,(-x)+100):1};
    if(flag[0]==-1||flag[1]==-1||flag[2]==-1)return d[u][x+100]=1;
    if(flag[0]==0||flag[1]==0||flag[2]==0)return d[u][x+100]=0;
    return d[u][x+100]=-1;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&l);
    for(int i=0; i<n; ++i)scanf("%d%d%d",&a[i],&b[i],&c[i]);
    memset(d,INF,sizeof d);
    int flag=dp(0,m+100);
    if(flag==1)puts("Good Ending");
    else if(flag==-1)puts("Bad Ending");
    else if(flag==0)puts("Normal Ending");
    return 0;
}

也可以写成递推的形式:

#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
int n,m,k,l;
int a[N],b[N],c[N];
int d[N][200+10];

int trans(int x)
{
    if(x<-100)x=-100;
    if(x>100)x=100;
    return x;
}

void solve()
{
    for(int i=0; i<=200; ++i)
    {
        int x=i-100;
        if(!(n&1))
        {
            if(x>=k)d[n][i]=1;
            else if(x<=l)d[n][i]=-1;
            else d[n][i]=0;
        }
        else
        {
            if(x>=k)d[n][i]=-1;
            else if(x<=l)d[n][i]=1;
            else d[n][i]=0;
        }
    }
    int f[3];
    for(int i=n-1; i>=0; --i)
        for(int j=0; j<=200; ++j)
        {
            int x=j-100;
            if(!a[i])f[0]=1;
            else f[0]=d[i+1][trans(x+a[i])+100];
            if(!b[i])f[1]=1;
            else f[1]=d[i+1][trans(x-b[i])+100];
            if(!c[i])f[2]=1;
            else f[2]=d[i+1][trans(-x)+100];
            if(f[0]==-1||f[1]==-1||f[2]==-1)d[i][j]=1;
            else if(f[0]==0||f[1]==0||f[2]==0)d[i][j]=0;
            else d[i][j]=-1;
        }
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&l);
    for(int i=0; i<n; ++i)scanf("%d%d%d",&a[i],&b[i],&c[i]);
    solve();
    if(d[0][m+100]==1)puts("Good Ending");
    else if(d[0][m+100]==-1)puts("Bad Ending");
    else if(d[0][m+100]==0)puts("Normal Ending");
    return 0;
}

还可以再进一步优化,将第一维设为滚动数组,大幅减小空间开销:

#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
int n,m,k,l;
int a[N],b[N],c[N];
int d[2][200+10];

int trans(int x)
{
    if(x<-100)x=-100;
    if(x>100)x=100;
    return x;
}

void solve()
{
    for(int i=0; i<=200; ++i)
    {
        int x=i-100;
        if(!(n&1))
        {
            if(x>=k)d[n&1][i]=1;
            else if(x<=l)d[n&1][i]=-1;
            else d[n&1][i]=0;
        }
        else
        {
            if(x>=k)d[n&1][i]=-1;
            else if(x<=l)d[n&1][i]=1;
            else d[n&1][i]=0;
        }
    }
    int f[3];
    for(int i=n-1; i>=0; --i)
        for(int j=0; j<=200; ++j)
        {
            int x=j-100;
            if(!a[i])f[0]=1;
            else f[0]=d[(i&1)^1][trans(x+a[i])+100];
            if(!b[i])f[1]=1;
            else f[1]=d[(i&1)^1][trans(x-b[i])+100];
            if(!c[i])f[2]=1;
            else f[2]=d[(i&1)^1][trans(-x)+100];
            if(f[0]==-1||f[1]==-1||f[2]==-1)d[i&1][j]=1;
            else if(f[0]==0||f[1]==0||f[2]==0)d[i&1][j]=0;
            else d[i&1][j]=-1;
        }
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&l);
    for(int i=0; i<n; ++i)scanf("%d%d%d",&a[i],&b[i],&c[i]);
    solve();
    if(d[0][m+100]==1)puts("Good Ending");
    else if(d[0][m+100]==-1)puts("Bad Ending");
    else if(d[0][m+100]==0)puts("Normal Ending");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/82625662