UVA11694 Gokigen Naname题解

写在前面

UVA的题需要自己读入一个 (T) 组数据,别被样例给迷惑了

Solution

每个格子只有两种填法且 (n le 7),暴力搜索两种填法,开cnt数组统计连接个数。

填一个格子,如果是 "",格子左上角和右下角的 (cnt++),如果是 "/",格子左下角和右上角的 (cnt++)。只有更改后的 (cnt) 小于等于目标 (cnt)才继续向下搜,否则回溯

发现每填一个格子,连接格子左上角的格点的个数就可以被确定,那么只有左上角的格点个数等于目标格点个数或没有要求才继续搜索,否则回溯

如果搜索到第 (n + 1) 列时,要额外判断边界第 (n + 1) 列的 (cnt)是否满足对应的个数
如果搜索到第 (n) 行时,要额外判断边界第 (n + 1) 行的 (cnt) 是否满足对应个数

如何保证无环?不难想到,只有在填 "/" 时才有可能出现环,那么在填 "/" 之前,先判断是否有环

如何处理点的坐标?把行看做十位,把列看做个位就好啦

  • 算法一:考虑可撤销并查集,然而我不会

  • 算法二:发现n很小,每次判断时 (n^2) 扫一遍建图,在 (dfs) 看看能否从左下角跑到右上角

  • 算法三:很显然算法二很傻逼,直接用并查集维护就好,加完边后判断左下角和右上角是否在同一并查集里,省去 (dfs) 的时间,注意清零!

最后输出方案就好啦

Code

我一开始建图跑的,后来也没改(因为懒

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 10;
const int INF = 1;
const int mod = 1;

struct edge{
	int from, to, nxt;
}e[10100 << 1];
int head[MAXN * MAXN], num_edge = 0;

int n;
int go[MAXN][MAXN];
int cnt[MAXN][MAXN], now[MAXN][MAXN];
bool flag = false, Flag = false;

int read(){
	int s = 0, f = 0;
	char ch = getchar();
	while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
	while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
	return f ? -s : s;
}

void add_edge(int from, int to){
	e[++num_edge] = (edge){from, to, head[from]}, head[from] = num_edge;
}

bool bl(int u, int fa, int end){
	for(int i = head[u]; i != -1; i = e[i].nxt){
		int v = e[i].to;
		if(v == fa) continue;
		if(v == end) {
			Flag = 1;
			return true;
		}
		bl(v, u, end);
		if(Flag) { return true;	}
	}
	return false;
}

bool pd(int sx, int sy, int ex, int ey){
	memset(head, -1, sizeof(head)); num_edge = 0;
	Flag = false;
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= n; ++j){
			if(now[i][j] == 0){
				add_edge(i * 10 + j, (i + 1) * 10 + j + 1);
				add_edge((i + 1) * 10 + j + 1, i * 10 + j);
			}
			if(now[i][j] == 1){
				add_edge((i + 1) * 10 + j, i * 10 + j + 1);
				add_edge(i * 10 + j + 1, (i + 1) * 10 + j);
			}
		}
	}
	if(bl(sx * 10 + sy, 0, ex * 10 + ey)) return 1;
	else return 0;
}

void dfs(int posx, int posy){
//	cout<<posx<<" "<<posy; 
//	orz;
	if(posx == n && posy == n + 1) { 
		if( ((cnt[posx + 1][posy] == go[posx + 1][posy]) || (go[posx + 1][posy] == 9)) && ((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9)) ) flag = 1; 
		return ; 
	}// 如果搜到最后一个点,说明已经找到答案。退出 
	if(posy == n + 1){ //如果这一行搜完了 
		if((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9) ) posx++, posy = 1;//换行 
		else  return ;// 如果已经确定的那个数并没有达到目标,返回 
	}//
	
	now[posx][posy] = 0;// 填 "" 
	cnt[posx][posy]++, cnt[posx + 1][posy + 1]++;// 对应位置加1 
	
	if(cnt[posx][posy] <= go[posx][posy] && cnt[posx + 1][posy + 1] <= go[posx + 1][posy + 1]) {//如果两个对应位置大于目标位置就不向下搜索 
		if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//如果已经确定的那个数没有达到目标,停止向下搜索 
			if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){
				dfs(posx, posy + 1);//
			}
		}
	}//
	if(flag) return ;// 如果找到答案就返回 
	cnt[posx][posy]--, cnt[posx + 1][posy + 1]--;//回溯 
	
	if(pd(posx + 1, posy, posx, posy + 1)){ return ;}
	
	now[posx][posy] = 1;// 填 "/"
	cnt[posx + 1][posy]++, cnt[posx][posy + 1]++;// 对应位置加1 
	
	if(cnt[posx + 1][posy] <= go[posx + 1][posy] && cnt[posx][posy + 1] <= go[posx][posy + 1]) {//如果两个对应位置大于目标位置就不向下搜索 
		if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//如果已经确定的那个数没有达到目标,停止向下搜索 
			if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){
				dfs(posx, posy + 1);//
			}
		}
	}
	if(flag) return ;// 如果找到答案就返回 
	now[posx][posy] = -1;//回溯 
	cnt[posx + 1][posy]--, cnt[posx][posy + 1]--;// 回溯 
}

int main()
{
//	freopen("gokigen.in","r",stdin);
//	freopen("gokigen.out","w",stdout);
	int T;
	T = read();
	while(T--){
		n = read();
		memset(now, -1, sizeof(now));
		memset(cnt, 0, sizeof(cnt));
		memset(go, 0, sizeof(go));
		flag = 0;
		char ch[10];
		for(int i = 1; i <= n + 1; ++i){
			cin>>(ch + 1);
			for(int j = 1; j <= n + 1; ++j){
				if(isdigit(ch[j])) go[i][j] = ch[j] - '0';
				else go[i][j] = 9;
			}
		}
		
		dfs(1, 1);
//		for(int i = 1; i <= n + 1; ++i){
//			for(int j = 1; j <= n + 1; ++j){
//				cout<<go[i][j]<<" ";
//			}
//			cout<<"
";
//		}
//		cout<<"
";
//		
//		for(int i = 1; i <= n + 1; ++i){
//			for(int j = 1; j <= n + 1; ++j){
//				cout<<cnt[i][j]<<" ";
//			}
//			cout<<"
";
//		}
//		cout<<"
";
		
		for(int i = 1; i <= n; ++i){
			for(int j = 1; j <= n; ++j){
				if(now[i][j] == 1) cout<<"/";
				else if(now[i][j] == 0) cout<<"\";
				else cout<<"s";
			}
			cout<<"
";
		} 	
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Silymtics/p/14226283.html