UVA11694 Gokigen Naname題解

寫在前面

UVA的題須要本身讀入一個 \(T\) 組數據,別被樣例給迷惑了ios

Solution

每一個格子只有兩種填法且 \(n \le 7\),暴力搜索兩種填法,開cnt數組統計鏈接個數。git

填一個格子,若是是 "\",格子左上角和右下角的 \(cnt++\),若是是 "/",格子左下角和右上角的 \(cnt++\)。只有更改後的 \(cnt\) 小於等於目標 \(cnt\)才繼續向下搜,不然回溯算法

發現每填一個格子,鏈接格子左上角的格點的個數就能夠被肯定,那麼只有左上角的格點個數等於目標格點個數或沒有要求才繼續搜索,不然回溯數組

若是搜索到第 \(n + 1\) 列時,要額外判斷邊界第 \(n + 1\) 列的 \(cnt\)是否知足對應的個數
若是搜索到第 \(n\) 行時,要額外判斷邊界第 \(n + 1\) 行的 \(cnt\) 是否知足對應個數spa

如何保證無環?不難想到,只有在填 "/" 時纔有可能出現環,那麼在填 "/" 以前,先判斷是否有環code

如何處理點的座標?把行看作十位,把列看作個位就好啦ci

  • 算法一:考慮可撤銷並查集,然而我不會get

  • 算法二:發現n很小,每次判斷時 \(n^2\) 掃一遍建圖,在 \(dfs\) 看看可否從左下角跑到右上角string

  • 算法三:很顯然算法二很傻逼,直接用並查集維護就好,加完邊後判斷左下角和右上角是否在同一並查集裏,省去 \(dfs\) 的時間,注意清零!it

最後輸出方案就好啦

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<<"\n";
//		}
//		cout<<"\n";
//		
//		for(int i = 1; i <= n + 1; ++i){
//			for(int j = 1; j <= n + 1; ++j){
//				cout<<cnt[i][j]<<" ";
//			}
//			cout<<"\n";
//		}
//		cout<<"\n";
		
		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<<"\n";
		} 	
	}
	return 0;
}
相關文章
相關標籤/搜索