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<bits/stdc++.h>
#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];
vector<int>vc[maxn],vv;
int dp[maxn][maxn][2];
int cnt[maxn][maxn];
int du[maxn];
template <typename T>
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;
    }
};
queue<node>q,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<vv.size();k++){
            int j=vv[k];
            rep(i,1,n){
            if(dp[j][i][0]!=0) {
                dp[j][i][0]=0;
                q.push(node{j,i,0});
            }
            }
        }
        read(sb);read(sa);
        while(!q.empty()){
            node s=q.front();q.pop();
            int x=s.x;
            int y=s.y;
            int z=s.z;
            if(z==0){
                for(int i=0;i<vc[y].size();i++){
                    int j=vc[y][i];
                    if(dp[x][j][1]){
                        dp[x][j][1]=0;
                        q.push(node{x,j,1});
                    }
                }
            }
            else {
                for(int i=0;i<vc[x].size();i++){
                    int j=vc[x][i];
                    if(++cnt[j][y]==du[j])
                    if(dp[j][y][0]){
                        dp[j][y][0]=0;
                        q.push(node{j,y,0});
                    }
                }
            }
        }

        printf("Case #%d: ",cas++);
        if(dp[sb][sa][0]) puts("Yes");
        else puts("No");
    }
    return 0;
}
/*
555
4 6
1 2
2 3
3 2
4 3
3 4
2 1
2 3
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章