Gym102220F Mini-game Before Contest(博弈论)

一般的博弈论都有必败态和必胜态,都是遇到某个状态发现是已经被决定的。

对于这题,先观察特殊状态,因为题目是个有向图,所以所有出度为0的点都是有特定状态的,因为他没有路可以走

我们设状态为f[i][j],表示在i这个点,是j行动,我们假定初始态是-1,表示平局,0表示A赢,1表示B赢,b[i]表示某人真的希望赢的那方

在出度为0的状态决定以后,只需要让他遍历能到当前点的点,暂时记为X,也就是存反向边,因为操作的顺序一定,所以前一个操作的就是i-1(1是前一个是6)

如果对于前一个操作人在X的期望和这个点相同,那么就可以更改状态,以下都默认是前一个人在X的期望状态

如果全部能到达X点的期望答案都与X的期望答案相反,那么X就是必败的。

这样只需要用一个队列就能扩展更新所有状态。

对于没有更新到状态的,那么就是表示平局情况

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=2e5+10;
int f[N][10];
int n,m;
int b[N],du[N][10];
string s,t;
vector<int> num[N];
int real1[N];
int pre(int x){
    if(x==1)
        return 6;
    else
        return x-1;
}
void solve(){
    queue<pll> q;
    int i,j;
    for(i=1;i<=n;i++){
        if(du[i][1]==0){
            for(j=1;j<=6;j++){
                if(s[j]=='A'){
                    f[i][j]=1;
                    q.push({i,j});
                }
                else{
                    f[i][j]=0;
                    q.push({i,j});
                }
            }
        }
    }
    while(q.size()){
        auto x=q.front();
        q.pop();
        for(auto e:num[x.first]){
            if(f[e][pre(x.second)]==-1){
                if(f[x.first][x.second]==b[pre(x.second)]){
                    f[e][pre(x.second)]=b[pre(x.second)];
                    q.push({e,pre(x.second)});
                }
                else{
                    du[e][pre(x.second)]--;
                    if(du[e][pre(x.second)]==0){
                        f[e][pre(x.second)]=b[pre(x.second)]^1;
                        q.push({e,pre(x.second)});
                    }
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        cin>>n>>m;
        memset(f,-1,sizeof f);
        memset(du,0,sizeof du);
        int i,j;
        for(i=0;i<=n;i++)
            num[i].clear();
        for(i=1;i<=m;i++){
            int a,b;
            cin>>a>>b;
            num[b].push_back(a);
            for(j=1;j<=6;j++){
                du[a][j]++;
            }
        }
        cin>>s>>t;
        s=" "+s;
        t=" "+t;
        for(i=1;i<=6;i++){
            real1[i]=s[i]-'A';
            b[i]=(t[i]-'0')^real1[i];
        }
        solve();
        for(i=1;i<=n;i++){
            if(f[i][1]==-1){
                cout<<'D';
            }
            else if(f[i][1]==1){
                cout<<'B';
            }
            else{
                cout<<'A';
            }
        }
        cout<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13939836.html