题面
题意
交互题.
给出一张二分图,左右两个点之间两两有边,每条边有一个权值且每条边的权值都不相同,Alice与Bob在上面玩游戏.每局游戏由Alice选择"增加"或"减少",Bob自动选择另外一项,然后Alice选择一个点并将棋子放在上面,Bob将它移动到一个与它相连的点,之后Alice与Bob轮流将棋子移动到一个之前没有移动到过的相邻点上.要求若Alice选的是"增加",则棋子移动所经过的边权必须大于棋子之前经过的边,"减少"则小于,Bob也是如此.
要求你选择成为Alice或Bob,并与交互库玩这个游戏,并取得胜利.
做法
让我们考虑Bob如何决策,假设Alice选择的起点在左边且选择的是"增加",然后将左右两边的点两两匹配,这样当棋子在左边的点时,Bob就将它移动到它的匹配点.下面考虑边权限制.
可以发现,如果上述方法无法让Bob获胜,当且仅当存在两组匹配(a,b)和(c,d),令(a,b)间的边权为A,令(c,d)间的边权为B,(c,b)间的边权为C,且A<C<B,这样当Bob将棋子由a移至b,Alice将棋子由b移至c后,Bob无法将棋子由c移至d.
也就是说,只要能找到一种匹配使得任意两组匹配都满足A>C或B<C,Bob就能获胜.
为了处理这个约束条件,可以将左边的点到右边的点的边权全部取反(将图中的所有无向边看作两条有向边),然后用稳定婚姻系统即可得到匹配,进而得到Bob的操作方案.
代码
#include<bits/stdc++.h>
#define N 110
using namespace std;
int T,n,now,pj,mm[N][N],a[N][N],b[N][N],pp[N],num[N][N],pos[N];
char str[5];
queue<int>que;
inline bool cmp(int u,int v){return a[pj][u]>a[pj][v];}
inline void calc()
{
memset(pp,0,sizeof(pp));
int i,j;
for(pj=1;pj<=n;pj++)
{
for(i=1;i<=n;i++)
{
num[pj][i]=i;
}
sort(num[pj]+1,num[pj]+n+1,cmp);
que.push(pj);
pos[pj]=1;
}
for(;!que.empty();)
{
int t=que.front();
que.pop();
for(int &j=pos[t];j<=n;j++)
{
i=num[t][j];
if(!pp[i+n])
{
pp[i+n]=t;
pp[t]=i+n;
break;
}
else if(b[i][t]>b[i][pp[i+n]])
{
int gg=pp[i+n];
pp[i+n]=t;
pp[t]=i+n;
que.push(gg);
break;
}
}
}
}
int main()
{
int i,j;
cin>>T;
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&mm[i][j]);
}
}
puts("B");fflush(stdout);
scanf("%s%d",str+1,&now);
if(str[1]=='D')
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
mm[i][j]=-mm[i][j];
}
}
}
if(now<=n)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
a[i][j]=-mm[i][j];
b[j][i]=mm[i][j];
}
}
}
else
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
a[i][j]=mm[i][j];
b[j][i]=-mm[i][j];
}
}
}
calc();
for(;now!=-1;)
{
printf("%d\n",pp[now]);
fflush(stdout);
scanf("%d",&now);
}
}
}