zoukankan      html  css  js  c++  java
  • 题解 UVA11694 【Gokigen Naname谜题 Gokigen Naname】

    题目

    题解

    考场上连暴力都不会打的码农题,深搜是真的难 /kk

    前置问题
    1. 怎么输出“”
    cout<<"\";
    

    2.怎么处理不在一个环里,可以考虑并查集,(f)数组的下标为该元素位于矩阵中的个数
    例如: 在$3 imes 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 .样例输入其实是有问题的
    样例输入:

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

    输出:

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

    再说一遍这是spj不要看样例不对就以为自己写错了,可能算法不一样也就不一样

    1.思路

    思路1 :

    上面的前置知识中已经解决了一个最大的问题,环的问题,剩下的就是怎么搜索
    ((1,1))开始搜索,逐行进行处理,因为每一个格子要不放""要不就是放"/"因为是spj我们可以考虑首先放"",然后判断放"/",种完全不反悔的深搜,一搜到底,适用的范围貌似不是很大

    思路2:

    可以考虑从((1,1))开始搜索, 首先考虑放“/” 如果不合法,那就回溯,重新放置"",这种想法想的很容易但是想要实现十分困难,反正这位大佬码量惊人,居然还真写出来了%%%%

    对于第一种思路的使用

    #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 == '
    ' && 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;
    }
    
  • 相关阅读:
    StackStorm简介及其部署
    Nginx系列(十二)——性能调整
    Nginx系列(十一)——通过日志进行故障排查
    Nginx系列(十)——可用性监控进阶
    Nginx系列(九)——容器/微服务
    Nginx系列(八)——数字媒体流
    Nginx系列(七)——HTTP/2
    Nginx系列(六)——安全控制
    Nginx系列(五)——认证
    Nginx系列(四)——配置文件自动化管理
  • 原文地址:https://www.cnblogs.com/-wzd233/p/14226690.html
Copyright © 2011-2022 走看看