acm專題學習之博弈(三)實戰+URAL - 2104

題意:Alice和Bob在玩一個遊戲,這個遊戲有個紙條,紙條的兩面有相同長度且由AB組成的字符串。每次其中一個人可以對摺一次紙條,直到不能再對摺爲止。如果最後紙條表面全是A則Alice獲勝,如果全是B則Bob獲勝,如果都不是則平局輸出Draw。Alice爲先手。

思路:dfs搜索,但是這裏也用到了博弈的知識。對摺每次只有偶數才能對摺,那麼結束條件就是紙條長度爲奇數的時候。這種兩面對摺,可以不用分兩個數組,一個數組直接相連就好了。(博弈知識)對於每個局面的先手,所以只要子結果裏面有一個是先手勝就ok了。而對於每個局面後手,必須要子結果全勝才能獲得出後手勝。那麼剩下的結果就是平局了。

代碼:

#include <algorithm>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1e5*5+5;
char s[maxn*2];//把兩面合在一個數組裏面
int n;
int suma[maxn*2],sumb[maxn*2];//前綴和計算a,b的個數
int dfs(int l,int r,int t){
    if((r-l+1)%2==1)return 2;
    if(suma[r]-suma[l-1]==r-l+1)return 1;
    if(sumb[r]-sumb[l-1]==r-l+1)return 0;
    int mid=(l+r)/2;
    int lson=dfs(l,mid,t^1);
    int rson=dfs(mid+1,r,t^1);
    if(lson==t||rson==t)return t;//先手只要子結果一個勝利就好了
    if(lson==rson&&lson==(t^1))return t^1;
    return 2;
}
int main(){
    scanf("%d",&n);
    scanf("%s",s+1);
    scanf("%s",s+n+1);
    for(int i=1;i<=2*n;i++){//前綴和計算a,b的個數
        suma[i]=suma[i-1];
        sumb[i]=sumb[i-1];
        if(s[i]=='A')
            suma[i]++;
        else
            sumb[i]++;
    }
    int ans=dfs(1,2*n,1);
    if(ans==1) printf("Alice\n");
    if(ans==0) printf("Bob\n");
    if(ans==2) printf("Draw\n");
    return 0;
}

總結:這道題,比賽的時候沒來得及看,但是感覺還是比較值得記錄以下的。一個是合併有關聯的數組簡化運算,還有前綴合和博弈局面先手後手必勝的條件使用。

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