題解 UVA11694 【Gokigen Naname謎題 Gokigen Naname】

題目

題解

考場上連暴力都不會打的碼農題,深搜是真的難 /kkios

前置問題
  1. 怎麼輸出「\」
cout<<"\\";

2.怎麼處理不在一個環裏,能夠考慮並查集,\(f\)數組的下標爲該元素位於矩陣中的個數
例如: 在$3 \times 3 $的矩陣中 \((2,2)\) 座標指的是交點的座標
能夠表示爲 5算法

(1,1)---->1
(1,2)---->2
(1,3)---->3
(1,4)---->4
(2,1)---->5
(2,2)---->6
(2,3)---->7
(2,4)---->8
(3,1)---->9
(3,2)---->10
(3,3)---->11
(3,4)---->12

若是兩個點位於同一個並查裏那就不能連邊,若是不在,那麼就能夠連邊
此並查集不一樣於通常的並查集
其初值不能爲0 ,並且其不能進行路徑壓縮,本身想一下就會明白,若是路徑壓縮會這樣wa數組

3 .樣例輸入實際上是有問題的
樣例輸入:app

2
3
1.1.
...0
.3..
..2.
5
.21...
..33.0
......
..33..
0..33.
....11

輸出:函數

\//
\\\
/\/
/\\//
//\\\
\\\//
\/\\/
///\\

再說一遍這是spj不要看樣例不對就覺得本身寫錯了,可能算法不同也就不同spa

1.思路

思路1 :

上面的前置知識中已經解決了一個最大的問題,環的問題,剩下的就是怎麼搜索
\((1,1)\)開始搜索,逐行進行處理,由於每個格子要不放""要不就是放"/"由於是spj咱們能夠考慮首先放"",而後判斷放"/",種徹底不反悔的深搜,一搜到底,適用的範圍貌似不是很大code

思路2:

能夠考慮從\((1,1)\)開始搜索, 首先考慮放「/」 若是不合法,那就回溯,從新放置"",這種想法想的很容易可是想要實現十分困難,反正這位大佬碼量驚人,竟然還真寫出來了%%%%blog

對於第一種思路的使用

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring> 
#include <string> 
#define ll long long

using namespace std;
const int N = 150;
const int dx[4] = {0, 0, 1, 1};
const int dy[4] = {0, 1, 0, 1};
int n ;
int mapp[50][50] ;
int cnt[N][N]; // 這個點已經鏈接了幾條邊 
int lim[N][N]; //一個格子能夠拓展的方向 
char ans[N][N]; // 一開始我是char想直接輸出,我也不知爲啥不行 
int f[N*N]; 
bool flag;

void print() {
	puts("");
	for(int i = 1 ; i <= n;i++) {
		for(int j = 1 ; j <= n ;j++) {
			cout<<mapp[i][j] <<" ";
		}
		puts("");
	}
}
//檢驗本身輸入的函數
bool check(int x,int y){
	if(mapp[x][y] == -1) return true;
	if(cnt[x][y] <= mapp[x][y] && cnt[x][y] + lim[x][y] >= mapp[x][y]) return true;
	return false ; 
} 
//判斷合法 

int findf(int x) {
	if( !f[x] ) return x;
	return f[x] = findf(f[x]);
}

void dfs(int x, int y) {
	if (y == n)	 {
		y = 1 , x++;
	} 
	if(x == n ) {
		flag = 1;
		return ;
	}
	// 這裏由於是逐行搜索,n++後,不會檢查第 n+1 行的交點,第n+1行下面已經沒有格子了 
	int f1 , f2 ,pd = 0;
	++cnt[x][y], ++cnt[x + 1][y + 1];
	--lim[x][y],--lim[x+1][y+1],--lim[x+1][y],--lim[x][y+1];
	//由於一個格子只能放一種 \ 或者 / 因此  一個格子的四個角都要減小拓展的方向 
	//第一種狀況 \ 
	for(int i = 0 ; i < 4 ;i++) {
		int tx = x + dx[i] , ty = y + dy[i];
		if(!check(tx,ty)) {
			pd = 1;
			break; 
		} 
	}
	if(!pd) {
		f1 = findf((x - 1) * n + y),f2 = findf(x * n + y + 1 ) ;
		if(f1 != f2) {
			ans[x][y] = 1; // 1 ---------> \ 
			f[f1] = f2;
			dfs(x,y+1);
			if(flag) return ;
			f[f1] = 0;
		} 
	}
	
	--cnt[x][y], --cnt[x+1][y+1];
	++cnt[x+1][y] ,++cnt[x][y+1];
	// 更換爲另外一種狀況  / 
	pd = 0;
	for(int i = 0 ; i < 4 ;i++) {
		int tx = x + dx[i] , ty = y + dy[i];
		if(!check(tx,ty)) {
			pd = 1;
			break; 
		} 
	}
	if(!pd) {
		f1 = findf(x * n + y ),f2 = findf((x - 1) * n + y + 1) ;
		if(f1 != f2) {
			ans[x][y] = 0; // 0 ------------> /
			f[f1] = f2;
			dfs(x,y+1);
			if(flag) return ;
			f[f1] = 0;
		} 
	}
	--cnt[x+1][y] ,--cnt[x][y+1];
	++lim[x][y] ,++lim[x+1][y+1] ,++lim[x+1][y], ++lim[x][y + 1] ;
	//深搜回溯 
	
}
int main() {
//	freopen("gokigen.in","r",stdin);
//	freopen("gokigen.out","w",stdout);
	int T;
	cin>> T;
	while(T--) {
    //
		memset(cnt , 0 , sizeof(cnt));
		memset(f,0,sizeof(f));
        flag = 0;
	//多組不清我是sb	
        cin>> n; n++;
		for(int i = 1 ; i <= n ;i++) {
			for(int j = 1 ;  j <= n  ;j++) {
				lim[i][j] = 4;
				char ch = getchar() ;
				if(ch == '\n' && i + j != 2 * n ) ch = getchar();
				if(ch == '.') mapp[i][j] = -1;
				else mapp[i][j] = (ch - '0'); 
				if((i == 1 || i == n) && (j == 1 || j == n)) {
					lim[i][j] = 1;
					continue;	
				}
				if(i == 1 || i == n || j == 1 || j == n) lim[i][j] = 2;
			}
		}
		dfs(1,1);
		for(int i = 1 ; i < n ;i++) {
			for(int j = 1 ; j < n ;j++) {
				if(!ans[i][j]) cout<<"/";
				else cout <<"\\"; 
			}
			puts("");
		}		
	}
	return 0;
}
相關文章
相關標籤/搜索