MarsOJ#MNS317

棋(chess)

【题目描述】

这是一个很有意思的益智类小游戏。

初始有一个19×1919×19的空棋盘。

有两个玩家(我们简称他们为小D和小L),两个人轮流进行操作,小D先手。

轮到小D的时候他会将一个空格子染黑而小L则会将一个空格子染白。

定义两个格子联通为两个格子相邻的边有一个相同。

定义联通块就是相同颜色且联通的两个格子连接后的联通块。

定义一个联通块的气为不在该联通块中且存在一个与其联通的在联通块的格子中空格子的数量。

现在我们考虑小D或小L的一次操作,如果将一个有颜色的格子染色则不合法。

当我们落下一颗子后。

首先,我们考虑在落下棋子后,考虑所有不包含该棋子的联通块,如果该联通块气为零,则该联通块包含的所有棋子消失,这个操作被称为提子。

如果在执行完上述操作后,落下棋子所在联通块的气为零。 则该落子不合法。

其中有一种特殊情况,当你一颗合法落子消除掉对方恰好一颗棋子时,对方下一步如果只恰好消除你上次落下的那一颗棋子,则对方的该落子不合法,这种情况被称为劫。

【输入格式】

从文件chess.in中读取数据

第一行输入一个数nn,表示尝试下棋次数。

接下来nn行,每行两个数xx,yy。

表示在(x,y)(x,y)落子。

如果该落子合法,则进行落子及提子,下次对方落子。

如果不合法,则不进行落子及提子,下次己方继续落子。

【输出格式】

输出到文件chess.out

对于第ii次尝试落子。

如果第ii次尝试落子不合法,只输出一行invalid

否则先输出一行valid,接着输出一个19×1919×19的矩阵,表示执行完该操作后棋盘的情况(1表示黑子,2表示白子,0表示空)

具体输出方式见样例。

【数据范围与约定】

  • n≤104n≤104 1≤x,y≤191≤x,y≤19

子任务 11:只有一组数据,输入给定,见下发文件chess1.in。分值:1010

子任务 22:只有一组数据,输入给定,见下发文件chess2.in。分值:1010

子任务 33:不存在劫的情况。分值:3030

子任务 44:无。分值:5050

样例见下发文件simple1.in simple1.out。(注无文件读写)

AC代码:

#include<bits/stdc++.h>//T3 
#define ll long long
#define g(a,b) __gcd(a,b)
#define F1(a,n,b) for(int a = 1;a <= n;a += b)
#define F2(a,b,n,c) for(int a = b;a <= n;a += c)
#define l2(a) log(a) / log(2)
#define pll pair<ll,ll>
#define ull unsigned long long
#define pii pair<int,int>
#define pq1 priority_queue<int>
#define pq2 priority_queue<int,vector<int>,greater<int>>
#define ui unsigned int 
using namespace std;
ll n;
ll dx[] = {0,1,-1,0,0},dy[] = {0,0,0,1,-1};
ll f[25][25],pre[25][25];
bool vis[25][25],v[25][25];
void dfs(ll x,ll y){
	if(vis[x][y])return;
	vis[x][y] = 1;
	for(int i = 1;i <= 4;++i){
		ll fx = x + dx[i],fy = y + dy[i];
		if(f[fx][fy] != f[x][y])continue;
		dfs(fx,fy);
	}
	return;
}
ll ask(ll x,ll y){
	memset(vis,0,sizeof(vis));
	dfs(x,y);
	ll q = 0;
	for(int i = 1;i <= 19;++i){
		for(int j = 1;j <= 19;++j){
			if(vis[i][j]){
				v[i][j] = 1;
				continue;
			}
			if(f[i][j])continue;
			bool flag = 0;
			for(int k = 1;k <= 4;++k){
				ll fx = i + dx[k],fy = j + dy[k];
				if(vis[fx][fy])flag = 1;
			}
			if(flag)q++;
		}
	}
	return q;
}
signed main(){
	cin>>n;
	ll x,y,px,py,tr = 1;
	px = py = 0;
	while(n--){
		cin>>x>>y;
		if(f[x][y]){
			puts("invalid");
			continue;
		}
		memcpy(pre,f,sizeof(pre));
		memset(v,0,sizeof(v));
		f[x][y] = tr;
		ll g,ax,ay;
		g = ax = ay = 0;
		for(int i = 1;i <= 19;++i){
			for(int j = 1;j <= 19;++j){
				if(!f[i][j])continue;
				if(f[i][j] == f[x][y])continue;
				if(v[i][j])continue;
				ll q = ask(i,j);
				if(!q){
					for(int u = 1;u <= 19;++u){
						for(int uu = 1;uu <= 19;++uu){
							if(vis[u][uu]){
								g++;
								ax = u;
								ay = uu;
								f[u][uu] = 0;
							}
						}
					}
				}
			}
		}
		ll q = ask(x,y);
		if(!q||(g == 1&&px == ax&&py == ay)){
			memcpy(f,pre,sizeof(f));
			puts("invalid");
			continue;
		}
		if(g == 1){
			px = x;
			py = y;
		}
		else {
			px = py = 0;
		}
		puts("valid");
		for(int i = 1;i <= 19;++i){
			for(int j = 1;j <= 19;++j){
				cout<<f[i][j]<<" ";
			}
			puts("");
		}
		tr = ((tr - 1) ^ 1) + 1;
	}
} 
/*

*/

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值