CodeForces - 1569B Chess Tournament

CodeForces - 1569B

AYIT609第一周周赛(2021)

A chess tournament will be held soon, where n chess players will take part. Every participant will play one game against every other participant. Each game ends in either a win for one player and a loss for another player, or a draw for both players.

Each of the players has their own expectations about the tournament, they can be one of two types:

a player wants not to lose any game (i. e. finish the tournament with zero losses);
a player wants to win at least one game.
You have to determine if there exists an outcome for all the matches such that all the players meet their expectations. If there are several possible outcomes, print any of them. If there are none, report that it’s impossible.

Input

The first line contains a single integer t (1≤t≤200) — the number of test cases.

The first line of each test case contains one integer n (2≤n≤50) — the number of chess players.

The second line contains the string s (|s|=n; si∈{1,2}). If si=1, then the i-th player has expectations of the first type, otherwise of the second type.

Output

For each test case, print the answer in the following format:

In the first line, print NO if it is impossible to meet the expectations of all players.

Otherwise, print YES, and the matrix of size n×n in the next n lines.

The matrix element in the i-th row and j-th column should be equal to:

+, if the i-th player won in a game against the j-th player;
-, if the i-th player lost in a game against the j-th player;
=, if the i-th and j-th players’ game resulted in a draw;
X, if i=j.

Example
input

3
3
111
2
21
4
2122

output

YES
X==
=X=
==X
NO
YES
X--+
+X++
+-X-
--+X

题意:下棋,有两种期望,1. 不输 2.至少赢一场
+是赢, -是输, =是平局, X是自己对自己的不存在的情况
第i个数是1表示期望第一种情况,是2表示期望第二种情况
要求满足所有玩家的期望,如果不能输出NO,能的话输出YES和任意一种情况

思路:画图,变换可知:要求不输的情况的行和列,除了X不存在的情况都可填=,并不影响结果
先不管顺序,把1都排在前面,2都排在后面

先看只有2的情况:
2:
自己跟自己对局,同时至少还要赢一局,不存在的情况
在这里插入图片描述

22:
2*2的格子,两个人都要赢一次,不存在的情况
在这里插入图片描述
在这里插入图片描述

222:
最小的成立情况,如下图(其中的一种情况)
在这里插入图片描述
2222:
已填充部分以满足至少赢一次的条件,空白部分可在满足题意的情况下随意填,为了方便我都是用=填充,在这里省略=
在这里插入图片描述
22222:
同上
在这里插入图片描述
上面说过是1的情况的行和列都可以只填充=
现在把1和2组合在一起展示一下一种情况:
221212:
先把是1的行和列填上=
在这里插入图片描述
再把=都移动到左边和上边
也就是把1都提到前面
112222
在这里插入图片描述
这样就得到右下角都是2的情况,根据上面讲过的2的情况知道,这是个4*4的可以填出符合题意的
在这里插入图片描述
把X去掉=补上得
在这里插入图片描述
增加2的个数再测试
在这里插入图片描述
由此可见是有规律的 (因为在上面填的时候就是有规律填的)

还以221212的例子来说
仔细观察可发现把1提前之前和之后的两个图每行都有3个空要填上 2的情况 对应的字符
而去掉X之后的2的情况也正好每行都有3个,
不妨 大胆猜想 一下,把去掉X的图例的字符依次放入空位就能符合题意
在这里插入图片描述
在这里插入图片描述
发现没毛病,多次验证之后也没毛病

因为我们规定的1的情况行和列都填=,得到的图形是 对称的
规定的2的情况也是“对称”的(+对称-)
两个组合一起也自然是符合题意的“对称”

对了还有判断不存在符合题意的图的条件是我这样推出来的:
只有2的情况才能影响到能不能得到符合题意的图
存在的条件是至少赢一次
假如有n个2,即在n*n的格子里
首先因为自己不能和自己对局所以先减去n得: n * ( n - 1 )
因为图是对称的有人赢就有人输,所以图里 赢的个数最多 时要再除以2得:n * ( n - 1 ) / 2
因为每人至少赢一次,有n人 所以 n * ( n - 1 ) / 2 >= n 才能满足题意
化简的 n * ( n - 3 ) >= 0
所以 n * ( n - 3 ) < 0 时可以直接输出NO

其实 符合题意 的就两种情况:
一种是没有2
一种是有2且2的个数 大于等于 3

思路有了,代码实现如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[60],map[60][60],cc[60];
int num1[60],num2[60];
int main()
{
	int t,n,n1,n2,i,j,k,mn2;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%s",&n,a+1);
		n1=n2=0;
		for(i=1;i<=n;i++)
			if(a[i]=='1')
				num1[n1++]=i;
			else
				num2[n2++]=i;
		mn2=n2;
		if(n2*(n2-3)<0)//n2*(n2-1)/2<n2
		{
			printf("NO\n");continue;//不成立的情况
		}
		printf("YES\n");
		memset(map,0,sizeof(map));
		for(i=1;i<=n;i++)
			for(j=0;j<n1;j++)
				map[num1[j]][i]=map[i][num1[j]]='=';//先把1的情况都填上'='
		for(i=1;i<=n;i++)
			map[i][i]='X';//自己和自己对局的情况填上'X'
		cc[0]='+';cc[n2-2]='-';
		for(i=1;i<n2-2;i++)
			cc[i]='=';//以上三行就是构造上面讲的去掉X的2的情况的第一行,因为是有规律的,下面的for循环是按规律填表
		for(i=1;i<=n;i++)
		{
			if(strlen(map[i]+1)==n)continue;//判断此行是否填满
			mn2--;k=mn2;
			if(k==n2-1)
				k=0;
			for(j=1;j<=n;j++)
			{
				if(map[i][j])continue;
				map[i][j]=cc[k++];
				if(k==n2-1)
					k=0;
			}
		}
		for(i=1;i<=n;i++)
			printf("%s\n",map[i]+1);
	}
	return 0;
}

以上都是我个人对此题目的理解和思路,有不对的地方欢迎指正,也欢迎和我分享自己的思路

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值