尝试构造这样一组匹配:满足对于任意两条匹配边 \(a\leftrightarrow b,c\leftrightarrow d\),若存在非匹配边 \(b\leftrightarrow c\) 且 \(w(b,c)<w(a,b)\),则一定有 \(w(c,d)\)。这样我们选择后手Bob,每次沿着匹配边走,一定能获得胜利(若Alice选择升序则令 \(w(i,j)=-w(i,j)\) 即可)。
发现这样的构造是一定存在的。对二分图左边的点,我们让优先级为从大到小;对于二分图右边的点,我们让优先级从小到大。然后使用稳定婚姻算法,发现正好可以满足以上条件。时间复杂度 \(O(n^2)\)。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=500,INF=1<<30;
int nxt[N],a[N][N],n,x,Rank[N][N],now;
char s[10];
queue <int> q;
void init()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
puts("B");fflush(stdout);
scanf("%s",s);
if(s[0]=='I')
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=-a[i][j];
}
scanf("%d",&x);
if(x>n)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=-a[i][j];
}
bool cmp(int x,int y)
{
return a[now][x-n]>a[now][y-n];
}
void prework()
{
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
Rank[i][j]=j+n;
now=i;
sort(Rank[i]+1,Rank[i]+1+n,cmp);
q.push(i);
}
for (int i=1;i<=n;i++)
a[0][i]=a[i][0]=INF;
for (int i=1;i<=n;i++)
nxt[i]=nxt[i+n]=Rank[i][0]=0;
while(!q.empty())
{
int x=q.front();q.pop();
if(x==0) continue;
while(nxt[x]==0)
{
int girl=Rank[x][++*Rank[x]];
if(a[x][girl-n]<a[nxt[girl]][girl-n])
nxt[nxt[girl]]=0,q.push(nxt[girl]),nxt[girl]=x,nxt[x]=girl;
}
}
}
void work()
{
prework();
for (int i=1;;i++)
{
if(x==-1||x==-2) return;
printf("%d\n",nxt[x]);fflush(stdout);
scanf("%d",&x);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
work();
}
return 0;
}