zoukankan      html  css  js  c++  java
  • 2020CCPC长春H.Combination Lock(二分图博弈)

      给一把锁,有一些数字被试过了,最多五个数字,每次将一个数字转动1(0-9成环),然后尝试能不能打开,每个数字只能尝试一次,问先手还是后手必胜。

      比赛的时候看了这个题,当时觉得不是计算sg函数的博弈,像是图论,模型转换也都比较对,但是根本没见过二分图博弈,实在想不出来,结束看是个很裸的二分图博弈。

      可以看出每次仅转动一个数字,必然导致所有数字的和奇偶发生变化,所以所有的数字构成一个二分图,剩下就是一个裸的二分图博弈了,看了https://www.pianshen.com/article/14591177358/这篇博客,觉得写得很清楚了。之前完全没做过二分图博弈的题,据cjb说去年ICPC南昌网络赛有过二分图博弈,南昌是去年唯一一场写过总结也是打的最炸的一场网络赛,然而我一点印象没有,只记得那场卡一个数学和dijkstra半天???只需要跑一个二分图匹配就好了,HK或者dinic都能过,复杂度$nsqrt(n)$

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <ll,ll> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define all(x) x.begin(),x.end()
    #define pb push_back
    #define fi first
    #define se second
    #define mes(a,b) memset(a,b,sizeof a)
    #define mp make_pair
    #define dd(x) cout<<#x<<"="<<x<<" "
    #define de(x) cout<<#x<<"="<<x<<"
    "
    #define debug() cout<<"I love Miyamizu Mitsuha forever.
    "
    const int inf=0x3f3f3f3f;
    const int N=400010,M=5000010;
    const int maxn=1e5+5;
    
    bool ban[maxn];
    int way[maxn];
    int head[N],ver[M],edge[M],Next[M],d[N];
    int e[maxn];
    int n,s,t,tot,maxflow;
    queue<int> q;
    vector<int> v[maxn];
    
    void add(int x,int y,int z)
    {
    //    dd(x);dd(y);de(z);
        ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
        ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot;
    }
    bool bfs()
    {
        mes(d,0);
        while(!q.empty()) q.pop();
        q.push(s);
        d[s]=1;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=head[x];i;i=Next[i])
                if(edge[i]&&!d[ver[i]])
                {
                    q.push(ver[i]);
                    d[ver[i]]=d[x]+1;
                    if(ver[i]==t) return 1;
                }
        }
        return 0;
    }
    int dinic(int x,ll flow)
    {
        if(x==t) return flow;
        int rest=flow,k;
        for(int i=head[x];i&&rest;i=Next[i])
        {
            if(edge[i]&&d[ver[i]]==d[x]+1)
            {
                k=dinic(ver[i],min(rest,edge[i]));
                if(!k) d[ver[i]]=0;
                edge[i]-=k;
                edge[i^1]+=k;
                rest-=k;
            }
        }
        return flow-rest;
    }
    
    int run(int l,int nn)
    {
        tot=1;
        s=nn,t=nn+1;
        rept(i,0,t) head[i]=0;
        rep(i,0,nn)
        {
            if(ban[i]) continue;
            if(way[i])
            {
                e[i]=tot+1;
                add(i,t,1);
                continue;
            }
            e[i]=tot+1;
            add(s,i,1);
            rep(j,0,2*l)
            {
                if(ban[v[i][j]]||v[i][j]>=nn) continue;
                add(i,v[i][j],1);
            }
        }
        int flow=0;
        maxflow=0;
        while(bfs())
            while(flow=dinic(s,inf)) maxflow+=flow;
        return maxflow;
    }
    
    void test()
    {
        int l,m,st;
        cin>>l>>m>>st;
        int nn=1;
        rep(i,0,l) nn*=10;
        rep(i,0,nn) ban[i]=0;
        rep(i,0,m)
        {
            int x;
            cin>>x;
            ban[x]=1;
        }
        int ans1=run(l,nn);
        if(edge[e[st]])
        {
            cout<<"Bob
    ";
            return ;
        }
        ban[st]=1;
        int ans2=run(l,nn);
        if(ans1==ans2) cout<<"Bob
    ";
        else cout<<"Alice
    ";
    }
    
    int cal(int x)
    {
        int ans=0;
        while(x)
        {
            ans+=x%10;
            x/=10;
        }
        return ans%2;
    }
    
    void init()
    {
        int n=100000;
        rep(i,0,n)
        {
            way[i]=cal(i);
            int x=i,mul=1;
            rep(j,0,5)
            {
                if(x%10==0) v[i].pb(i+9*mul);
                else v[i].pb(i-mul);
                if(x%10==9) v[i].pb(i-9*mul);
                else v[i].pb(i+mul);
                mul*=10;
                x/=10;
            }
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        init();
        int q;
        cin>>q;
        while(q--) test();
        return 0;
    }
  • 相关阅读:
    Vue2.0一个login跳转实例
    canvas动画—圆形扩散、运动轨迹
    根据地理信息绘画的html5 小游戏
    用vue开发一个猫眼电影web app
    微信小程序 iphone6 和 iphone6plus 如何设置rpx单位,通俗易懂的方法
    前端实例练习
    为表单加上即时通讯的能力
    MongoDB学习笔记4——GridFS基础
    剑指Offer(Java版)第十三题:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
    剑指Offer(Java版)第十一题
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/13946648.html
Copyright © 2011-2022 走看看