2014-2015 ACM-ICPC, Asia Xian Regional Contest Problem H. The Problem to Make You Happy(博弈,记忆化搜索)

题意:

给你n(<=100)个点m(<=n*(n-1))条边的有向简单图,Alice和Bob(两个人都足够聪明)在这个图上玩游戏,两个人轮流沿着有向图走,一次只能走一条边,Bob先走,如果Alice和Bob走到同一个点,或者Bob无法走了,则Bob输,否则Bob赢(Alice永远追不上Bob或者Alice无路可走)。如果Bob能赢输出Yes,否则输出No。

思路:

考虑记忆化搜索。但是由于图并不是DAG,我们只能倒着从已知的状态往前推,从而找出所有的Bob的必败态。

dp[i][j][k]表示Bob在i点,Alice在j点,轮到k(k=0表示该Bob走了,k=1表示该Alice走了)走了时,Bob是否能赢(不能则值为0)。

显然可以找出两种Bob的必败态:

1、该Bob走了,并且无路可走

2、无论该谁走了,Bob和Alice在同一个点

将两种必败态的所有点加入队列,假设当前Bob在x点,Alice在y点,依次判断:

1、如果下一步该Bob走了并且是(Bob的)必败态,那么Alice直接从y的前一个点ny走到y。将得到的新的必败态(x,ny,1)加入队列。

2、如果下一步该Alice走了并且是(Bob的)必败态,那么枚举x的前驱节点nx,如果nx的所有后继状态都是必败态,那么得到新的必败态(nx,y,0)加入队列。

由于nx的所有后继状态都是必败态我们才去判断它,所以可以先记录好每个节点的出度,然后倒着建图,用一个cnt[i][j]表示i的(倒着建图的)后继节点的必败态数量,这样更方便判断。

代码:

#include
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=4e2+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
int a[maxn],c[maxn];
int ans,tmp;
int flag;
char s[maxn];
bool ok[maxn];
vectorvc[maxn],vv;
int dp[maxn][maxn][2];
int cnt[maxn][maxn];
int du[maxn];
template 
inline void read(T &X)
{
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
struct node{
    int x,y;
    int z;
    node(){}
    node(int xx,int yy,int zz){
        x=xx;y=yy;z=zz;
    }
};
queueq,p;
int main()
{
    int T,cas=1;
    read(T);
    while(T--)
    {
        read(n);read(m);
        q=p;
        ans=0; flag=0;
        int sb,sa;
        rep(i,1,n) {vc[i].clear();du[i]=0;}
        rep(i,0,n)
        rep(j,0,n)
        rep(k,0,1){
            dp[i][j][k]=-1;
            cnt[i][j]=0;
        }
        rep(i,1,n)
        rep(k,0,1){
            dp[i][i][k]=0;
            q.push(node{i,i,k});
        }
        vv.clear();
        rep(i,1,m){
            int x,y;
            read(x);read(y);
            vc[y].push_back(x);
            du[x]++;
        }
        rep(i,1,n) if(!du[i]){
            vv.push_back(i);
        }
        for(int k=0;k

 

你可能感兴趣的:(数论:博弈,数据结构:动态规划,数据结构:DFS/BFS,运维)