codeforces1161F Zigzag Game

190 篇文章 2 订阅
13 篇文章 0 订阅

题面

题意

交互题.
给出一张二分图,左右两个点之间两两有边,每条边有一个权值且每条边的权值都不相同,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);
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值