1. 程式人生 > 其它 >Day4(搜尋)

Day4(搜尋)

技術標籤:c++強化學習

圖:

一、圖的類別:有向圖與無向圖
二、圖的概念:圖由點和線組成,點之間的線,分有方向和無方向。
三、建立圖,就是創建出節點和節點之間的線。

建邊:
#include<bits/stdc++.h>
using namespace std;

#define LL long long

const int N=100000+10;
const int M=100+10;

vector<int>G[N];
//x->y
void way1(){
	G[x].push_back(y);  //加邊方式
	
	int sz=G[x].size();  //遍歷方式 
	for
(int i=0;i<sz;i++){ int to=G[x][i]; } } //鏈式前向星 int tot,ver[N<<1],Next[N<<1],head[N]; //tot標號,ver[]儲存每個編號的邊連出去的點,Next[]往前連線的邊的編號,head[]最後一個編號的邊 void add(int u,int v){ //新增一條從u->v的邊 ++tot;ver[tot]=v; Next[tot]=head[u];head[u]=tot; } void way2(){ add(x,y); //加邊方式 for(int i=
head[x];i;i=Next[i]){ //遍歷方式 int to=ver[i]; } } int main(){ memset(head,0,sizeof head); }

bfs—廣度優先搜尋

找v0到v6一條最短的路
在這裡插入圖片描述
①.搜尋v0 ②.搜尋v1,v2,v3 ③.搜尋到v6

例題:
通過一年學習在杭州,宜芬飛終於到達家鄉寧波。離開寧波一年,葉芬飛有很多人要見面。尤其是好朋友梅塞基
益芬飛的家在農村,但梅塞基的家在市中心。因此,伊芬菲與美世基安排在肯德基見面。寧波有很多肯德基,他們想選一個讓總時間到它最小的。
現在給你一張寧波地圖,伊芬菲和美世基都可以上下移動,向左移動,右移到相鄰的公路上,花費11分鐘。

輸入

輸入包含多個測試用例。
每個測試用例包括,前兩個整數 n,m. (2<\n,m<=200)。
下 n 行,每行包含 m 字元。
‘Y’ 表示伊芬飛初始位置。
“M” 表示默塞基的初始位置。
“#” 禁止道路;
". "道路。
‘@’ Kcf

輸出

對於每個測試用例輸出的最小總時間,伊芬菲和美世基到達肯德基之一。你可能肯定總是有一個肯德基, 可以讓他們見面。

示例輸入

4 4
Y.#@

.#…
@…M
4 4
Y.#@

.#…
@#.M
5 5
Y…@.
.#…
.#…
@…M.
#…#

示例輸出

66
88
66

程式碼:
#include<bits/stdc++.h>
using namespace std;
 
#define pii pair<int,int>
//(x,y)  pii Point=make_pair(x,y)
//獲取x  x=Point.first;
//獲取y  y=Point.second; 
 
const int N=200+10;
const int M=10;
const int inf=0x3f3f3f3f;   //無窮大 
 
char s[N][N];
int sx[M],sy[M];
int n,m,dis[M][N][N];
int dx[M]={0,0,1,-1};
int dy[M]={1,-1,0,0};
 
void bfs(int id){
	queue<pii>q;   //先進先出 
	q.push(make_pair(sx[id],sy[id]));
	dis[id][sx[id]][sy[id]]=0;
	while(!q.empty()){
		int x=q.front().first,y=q.front().second;
		q.pop();  //記得 
		for(int i=0;i<4;i++){
			int xx=x+dx[i],yy=y+dy[i];   //下一步要走的點 
			if(1<=xx && xx<= n && 1<=yy && yy<=m && dis[id][xx][yy]==inf && s[xx][yy]!='#'){
				dis[id][xx][yy]=dis[id][x][y]+1;
				q.push(make_pair(xx,yy));
			}
		}
	}
}
 
int main(){
	while(scanf("%d %d",&n,&m)!=EOF){
		memset(dis,inf,sizeof dis);
		for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
		for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
			if(s[i][j]=='Y')sx[0]=i,sy[0]=j;
			if(s[i][j]=='M')sx[1]=i,sy[1]=j;
		}
		bfs(0),bfs(1);
		int res=inf;
		for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(s[i][j]=='@'){
			res=min(res,dis[0][i][j]+dis[1][i][j]);
		}
		printf("%d\n",res*11);
	}
} 

dfs—深度優先搜尋

找v0到v6一條路(無需最短)
在這裡插入圖片描述
①V0->V1->V4,此時到底盡頭,仍然到不了V6,原路返回到V1去搜索其他路徑
②V0->V1->V2->V6,,找到目標節點,返回有解

例題:
在N*N的方格棋盤放置了N個皇后,使得它們不相互攻擊(即任意2個皇后不允許處在同一排,同一列,也不允許處在與棋盤邊框成45角的斜線上。
你的任務是,對於給定的N,求出有多少種合法的放置方法。

輸入

共有若干行,每行一個正整數N≤10,表示棋盤和皇后的數量;如果N=0,表示結束。

輸出

共有若干行,每行一個正整數,表示對應輸入行的皇后的不同放置數量。

示例輸入

1
8
5
0

示例輸出

1
92
10

程式碼:
#include<bits/stdc++.h>
using namespace std;
 
const int N =10+10;
 
int f[N],vis[N],n,cnt;  //vis[i] 代表第i列之前已經被第vis[i]行放置 
 
bool check(int row,int col){   //判斷第row行第col列能不能放置棋子 
	if(vis[col])return false;
	for(int i=1;i<=n;i++){   //45° 
		if(vis[i] && abs(i-col)==abs(vis[i]-row))return false;
	}
	return true;
}
 
void dfs(int now){   //當前準備放置第now行 
	if(now==n+1){    //是否對答案有貢獻 
		cnt++;
		return;
	}
	for(int i=1;i<=n;i++){
		if(check(now,i)){  
			vis[i]=now;  //第i列已經由第now行放置 
			dfs(now+1);  //放置下一行 
			vis[i]=0;    //還原 
		}
	}
}
 
int main(){
	for(n=1;n<=10;n++){
		memset(vis,0,sizeof vis);
		cnt=0;
		dfs(1);
		f[n]=cnt;
	}
	int x;while(scanf("%d",&x)!=EOF){
		if(x==0)break;
		printf("%d\n",f[x]);
	}
}