CF1147F Zigzag Game

Link
我们知道如果没有边权大小的限制那么一定先手必胜,因此我们不妨猜测在有了边权大小的限制之后仍然是先手必胜。
不失一般性,假设Alice选择I并将棋子放在某个左侧点。
我们任取一组最大匹配中的两条边\((u,v),(p,q)\),那么我们希望构造出这样的情况:
若Alice将棋子从\(v\)移至\(p\)是合法的,那么Bob将棋子从\(p\)移到\(q\)也是合法的。
这样的话需要满足\(w(u,v),w(p,q)
我们称一组匹配是不好的当且仅当匹配中存在两条边\((u,v),(p,q)\)使得\(w(u,v)
我们现在的任务是找到一组好的匹配。
这实际上就是一个稳定婚姻问题,令左侧点的偏好为按照边权生序排序,右侧点的偏好为按照边权降序排序即可。
稳定婚姻问题是有一个\(O(n^2)\)的解法的:
一个单身的男生向自己尚未表白的最喜欢的女生表白。
如果该女生现在没有男朋友,那么表白成功。
如果该女生已经有男朋友,并且更喜欢自己现在的男朋友,那么表白失败。
如果该女生已经有男朋友,并且更喜欢现在表白的这个男生,那么表白成功,之前的男朋友重新进入单身状态。

#include
#include
#include
#include
#include
int read(){int x;scanf("%d",&x);return x;}
int n,e[51][51],rank[51][51],next[101],pos[51];
std::vectorvec[51],t;std::queueq;
void work(int f)
{
    memset(pos+1,0,n<<2),memset(next+1,0,n<<3);
    for(int i=1,j;i<=n;++i) for(q.push(i),vec[i].clear(),j=1;j<=n;++j) vec[i].push_back(j);
    for(int i=1;i<=n;++i) std::sort(vec[i].begin(),vec[i].end(),[&](int a,int b){return (e[i][a]e[b][i])^f;});
    for(int j=0;j<(int)t.size();++j) rank[i][t[j]]=j+1;
    }
    for(int u,v;!q.empty();)
    for(u=q.front(),q.pop();!next[u];)
    {
        v=vec[u][pos[u]++];
        if(!next[v+n]||rank[v][next[v+n]]>rank[v][u])
        {
        next[next[v+n]]=0;
        if(next[v+n]) q.push(next[v+n]);
        next[v+n]=u,next[u]=v+n;
        }
    }
}
int main()
{
    for(int t=read(),p;t;--t)
    {
    n=read();
    for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) e[i][j]=read();
    printf("B\n"),fflush(stdout);
    if(getchar(),getchar()=='D') for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) e[i][j]=-e[i][j];
    for(work((p=read())>n);~p;p=read()) printf("%d\n",next[p]),fflush(stdout);
    }
}

你可能感兴趣的:(CF1147F Zigzag Game)