1. 程式人生 > 實用技巧 >2021.1.3搜尋測試

2021.1.3搜尋測試

【雜言】:

寡人怎麼也沒想到 T1寫掛了,

\(T1\)】:

【題目描述】:

給出一個n個未知數的方程,\(x_1,x_2,x_3......x_n\)\(x_1+x_2+x_3....+x_n==S\)的正整數解的個數,並且要保證,對於任意\(i (1<=i< n)\) \(x_i\)\(x_{i+1}\)相差不大於\(p\)

【資料範圍】:

對於 \(30%\) 資料 \(2<=n<=10 ,p=0,S<=30;\)對於 \(100%\) 資料 \(2<=n<=10,p<=3 , S<=30;\)保證資料有梯度。

【考場程式碼】:(只有三十分,合著我暴力掛了):

/*
 by : Zmonarch 
 知識點 :搜尋 
*/
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <cstring>
#define int long long
using namespace std ;
inline int read()
{
	int x = 0 , f = 1 ; char ch = getchar() ;
	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ; 
}
int n , tot , s , p ;  
void search(int now , int last ,int rest)
{
	//printf("sum : %d\n" ,rest) ;
	if(now == n + 1 ) //現在已經加到了最後一個數 
	{
		if (rest == 0) tot ++ ;//方案數++
		return ;
	}
	for(int i = 1 ; i < s && abs(i - last ) <= p; i++)//前一個數和後一個數不能超過p  
	{
		search(now + 1 , i , rest - last - i) ;
	}
}
signed main()
{
//	freopen("math.in" , "r" , stdin) ;
//	freopen("math.out" , "w" , stdout) ;
	n = read() , s = read() , p = read() ;
	//for(int i = 1 ; i <= s ; i++)
	if(p == 0) //因為是正整數, 所以如果相差為零, 那麼也就只有一種情況, 那就是全部都是同一個數的時候,除不盡就不是正整數了 
	{ //這裡的相差是絕對值, 特判一下 , 
		if(s % n == 0) printf("1") ;
		else printf("0") ; 
	} 
	else 
	{
		search( 0  , 0 ,s) ;	
		printf("%lld", tot) ;
	}
	return 0 ;
}

【Std】:

/*
 by : Zmonarch 
 知識點 :搜尋 
*/
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <cstring>
#define int long long
using namespace std ;
inline int read()
{
	int x = 0 , f = 1 ; char ch = getchar() ;
	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ; 
}
int n , tot , s , p ;  
void search(int now , int last ,int rest)
{
	if(now == n) //現在已經加到了最後一個數 
	{
		if (abs(rest - last) <= p)  tot ++ ;
		return ;
	}
	for(int i = max((long long)1 , last - p) ; i <= min(last + p , rest - n + i); i++)//前一個數和後一個數不能超過p  
	{
		search(now + 1 , i , rest - i) ;
	}
}
signed main()
{
	//freopen("math.in" , "r" , stdin) ;
	//freopen("math.out" , "w" , stdout) ;
	n = read() , s = read() , p = read() ;
	//for(int i = 1 ; i <= s ; i++)
	if(p == 0) //因為是正整數, 所以如果相差為零, 那麼也就只有一種情況, 那就是全部都是同一個數的時候,除不盡就不是正整數了 
	{ //這裡的相差是絕對值, 特判一下 , 
		if(s % n == 0) printf("1") ;
		else printf("0") ; 
	} 
	else 
	{
		for(int i = 1 ; i <= s-(n-1) ; i++)
		search( 2 , i ,s - i) ;	
		printf("%lld", tot) ;
	}
	return 0 ;
}

【T2】:

【題目描述】:

給出一個\(n \times n\)的網格,有一些格子是障礙,再給出一對起點終點,求從起點到終點需要的最小步數,每次可以從一個格子走到上下左右4相鄰的四個格子裡.

【輸入】:

第一行一個整數\(n\)
以下\(n\)\(n\)個整數,描述整個網格,其中\(0\)表示沒有障礙,\(1\)表示有障礙。
最後一行四個整數,\(Sx,Sy,Tx,Ty\),描述起點和終點。

【輸出】 :

輸出最少步數。
如果永遠走不到輸出-1。

【資料範圍】:

對於30%的資料,\(n<=10\)
對於 100%的測試資料,\(n<=1000\)

【考場程式碼】:

大水題 ,一眼切 , 直接過。

/*
 by : Zmonarch
 知識點 : 搜尋 
*/
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <cstring>
#define int long long 
using namespace std ;
const int kmaxn = 1000 + 1 ;
const int inf = 2147483647 ; 
inline int read()
{
	int x = 0 , f = 1 ; char ch = getchar() ;
	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ;
}
int n , vis[kmaxn][kmaxn] , f[kmaxn][kmaxn] , sx , sy , tx , ty , ans = inf;
int dx[4] = {0 , 0 , 1 , -1} ;
int dy[4] = {1 , -1 , 0 , 0} ;
struct node
{
	int x , y , step ;
}; 
queue<node> q ; 
bool check(int x , int y)
{
	return ( x <= n && y<=n && x >= 1 && y >= 1) ;
}
void search(node now)
{
	q.push(now) ;
	while(!q.empty())
	{
		node u = q.front() ;
		q.pop() ;
		int x = u.x , y = u.y , step = u.step ;
		if(step >= ans) continue ; //小小的優化,截去不符合條件的搜尋枝 
		if(u.x == tx && u.y == ty)
		{
			ans = min(ans , step) ;
		}
		for(int i = 0 ; i < 4 ; i++)
		{
			int kx = x + dx[i] ;
			int ky = y + dy[i] ;
			if(!check(kx , ky)) continue ; //檢查邊界 
			if(vis[kx][ky]) continue ;
			vis[kx][ky] = 1 ;
		//	printf("%d %d\n" , kx , ky) ;
			node nxt = {kx , ky , step + 1} ;
			q.push(nxt) ;
		}
	}
}
signed main() 
{
	//freopen("grid.in" , "r"  , stdin) ;
	//freopen("grid.out" , "w" , stdout) ;
	n = read() ;
	for(int i = 1 ; i <= n ; i++)
	{
		for(int j = 1 ; j <= n ; j++)
		{
			vis[i][j] = read() ;
		}
	}
	sx = read() , sy = read() , tx = read() , ty = read() ;
	if(vis[sx][sy] || vis[tx][ty]) 
	{
		cout <<"-1" ;
		return 0 ;
	}
	node ss = {sx , sy , 0} ;
	search(ss) ;
	if(ans != inf) printf("%lld" , ans) ;
	else printf("-1") ; 
	return 0 ;
}

【T3】

【題目描述】 :

戈蘭斜是一種在帶數字的網格上玩的日本拼圖遊戲。目標是在網格的每個單元格中繪製對角線,連線到每個格點的對角線個數等於他對應的數字。另外,禁止對角線形成環。

第 一個 圖給 出了遊戲的初始狀態。 第二個圖給出了對應的一個解答。資料保證問題一定存在至少一解。

【輸入】:

輸 入的 第一 行包含一個的單個整數 \(n\)表示棋盤的尺寸,棋盤是一個正方形。
然後緊接 \(n+1\)行。包含網格的初始狀態。每行為一個含\(n+1\)個字元的字串,字元要麼為一個數字,要麼為一個(‘.’),
其中數字都是\(0\)\(4\)之間的任意整數,‘.’表示連線到此格點的對角線數沒有限制

【輸出】:

輸出包含 \(n\)行,每行 \(n\) 個字元,每個字元為斜槓或反斜槓表示如何填充相應的棋盤。

【資料範圍】 :

對於 \(100%\)的資料 , \(n\leq 7\)