題面
題意
交互題.
給出一張二分圖,左右兩個點之間兩兩有邊,每條邊有一個權值且每條邊的權值都不相同,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);
}
}
}