Day4(搜尋)
圖:
一、圖的類別:有向圖與無向圖
二、圖的概念:圖由點和線組成,點之間的線,分有方向和無方向。
三、建立圖,就是創建出節點和節點之間的線。
建邊:
#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]);
}
}