廣搜優化題目總結

2022-08-21 21:03:14 字數 4681 閱讀 5696

題面

這道題之前打過,但那時候打題太水了,沒有真正掌握這道題的知識點。(果然我還是太蒻了)

這道題的解法是先建邊,對於每乙個單位正方形,將有邊相連的兩個對角建一條長度為0的無向邊,另外兩個對角建一條長度為1的無向邊。然後可以跑最短路或者用雙端佇列bfs(0-1bfs)。

跑最短路的話要注意由於是網格圖spfa會炸掉,所以要用堆優化的dijkstra( 不會不加堆優化的dijkstra (_) )

因為在練習廣搜,所以我用的是雙端佇列bfs

當我們遇到邊權只有1的情況時,顯然直接bfs,然後第一次訪問到某個點的「時間」就是到它的最短路徑

當邊權同時存在1和0兩種情況時,我們就可以採用雙端佇列bfs,也叫作0-1bfs,就是訪問時,若邊權為0,則把目標點v放在隊首,若邊權為1,則把目標點放在隊尾,這樣是為了使得邊權為0時的目標點v先被訪問。

我按照這個思路做了,但卻wa了,後來我一看題解,佇列裡維護的居然不是點,而是邊,我一直想不通為什麼,找了半天也只有題解模糊地寫到,然後我就自己手玩了一把,發現如果是維護點,那麼有可能會出現這樣的情況:顯然如果邊權為0,那麼目標點v與點u應該處於廣搜的同一層,但如果是維護點,就可能會出現點v在被點u訪問到之前被下一層的點提前訪問了(也就是由這一層的點通過邊權為1的邊得到的目標點vv訪問過來(因為如果是維護點,那麼就會像是乙個深搜的過程,會在我把這一層訪問完之前,下一層的點先把這一層的點訪問了))。但如果我們是維護邊的話,那麼將會起到乙個滯留的作用,能夠留給我時間,讓我先把這一層的訪問完了,在訪問下一層。

這道題我還有乙個收穫就是知道了鏈式前向星還能儲存入邊,以前我的不知道來著,,,

這是我wa掉的訪問點的**(注釋掉的是我手玩搜尋過程的**)

#include #include #include #include #include using namespace std;

#define maxn 280000

int n,m;

dequeq;

int fir[maxn],nxt[maxn*2],vv[maxn*2],edg[maxn*2];

int tot=0,ans=0;

int vis[maxn],dis[maxn];

void add(int u,int v,int w)

//int room[1000];

int id(int x,int y)

void bfs()

// printf("\n");

// for(int i=cnt;i>=1;i--)q.push_front(room[i]);

int u=q.front();q.pop_front();

// printf("u=%d dis[u]=%d\n",u,dis[u]);

for(int i=fir[u];i;i=nxt[i])

}}int main()

else}}

bfs();

/* for(int i=1;i<=n+1;i++)

for(int j=1;j<=m+1;j++)

printf("id(%d,%d)=%d\n",i,j,id(i,j));

for(int i=1;i<=id(n+1,m+1);i++)

printf("dis[%d]=%d\n",i,dis[i]);

printf("id(n+1,m+1)=%d\n",id(n+1,m+1));printf("dis[%d]=%d\n",id(n+1,m+1),dis[id(n+1,m+1)]);*/

if(dis[id(n+1,m+1)]==-1)printf("no solution\n");

else printf("%d\n",dis[id(n+1,m+1)]);

return 0;

}

這是正解

#include #include #include #include #include using namespace std;

#define maxn 2800000

int n,m;

dequeq;

int fir[maxn],nxt[maxn*4],uu[maxn*4],vv[maxn*4],edg[maxn*4];

int tot=0,ans=0;

int vis[maxn],dis[maxn];

void add(int u,int v,int w)

int id(int x,int y)

void bfs()

}}int main()

else}}

bfs();

if(dis[id(n+1,m+1)]==-1)printf("no solution\n");

else printf("%d\n",dis[id(n+1,m+1)]);

}return 0;

}

可能性一共用8!=40320種

種類極少,所以直接用map去重(注意map速率較慢,聽說插入和查詢都是logn),也可以用康拓展開(乙個排列在全排列中的順序)來做

#include#include#include#include#include#includeusing namespace std;

string str1,ansstr,cstr;int a[10];int pd=0;

queue q;

mapm;

void opa(string str)

}void opb(string str)

}void opc(string str)

}void bfs()

q[2][100000];

int n;

int ans=0;

int l[2],r[2];

int v[2][310][310],dis[2][310][310];

int dx[9]=;

int dy[9]=;

int check(int x,int y)

int expand(int k)}}

return 0;

}void bfs()

l[0]=r[0]=1;l[1]=r[1]=1;

v[0][q[0][1].x][q[0][1].y]=1;

v[1][q[1][1].x][q[1][1].y]=1;

while(l[0]<=r[0]&&l[1]<=r[1])

q[2][100000];

int l[2],r[2];

int vis[2][100000];

int dx[5]=;

int dy[5]=;

int check(int x,int y)

int ans=0;

int expand(int k)

for(int i=1;i<=4;i++)

//printf("hashs=%d hashe=%d\n",hashs,hashe);

if(vis[k][hashe]!=0)

vis[k][hashe]=vis[k][hashs]+1;

r[k]++;

for(int ii=1;ii<=4;ii++)

for(int jj=1;jj<=4;jj++)

if(vis[1-k][hashe]!=0)

q[k][l[k]].a[tx][ty]=0;q[k][l[k]].a[i][j]=1;}}

}return 0;

}void bfs()

if(hashs==hashe)

vis[0][hashs]=1;vis[1][hashe]=1;

while(l[0]<=r[0]&&l[1]<=r[1])

to[55][55][6];

char ch[55][55];

char goal[10010];

int dx[5]=;

int dy[5]=;

int check(int x,int y)

void deal_first()

if(!check(tx,ty))continue;

to[i][j][k].x=tx;to[i][j][k].y=ty;}}

}}struct jp;

queueq;

int vis[55][55];

void bfs()

); vis[1][1]=tim;

while(!q.empty())

if(vis[tx][ty]bfs水題

直接列舉每個未訪問的點跑一遍bfs就可以了,一開始我還在想儲存1000000個queue,然後再跑,後來發現求bfs的時候順帶掃瞄就完了。

#include #include #include using namespace std;

#define mp make_pair

#define pr pairint n;

int a[1005][1005],vis[1005][1005];

int dx[9]=;

int dy[9]=;

int check(int x,int y)

int pd1,pd2;

queueq;

void bfs(int x,int y)

if(a[tx][ty]>a[a.first][a.second])pd2=0;

if(a[tx][ty]未完待續...(已update完於2019.8.15)

廣搜的優化

其實主要的思想與深搜類似 放兩個題吧 這個題思想很好 一開始我都不知道qwq include include include include include using namespace std const int n 300000 int t,r,c,n intdis n p n cnt boo...

廣搜 BFS 總結

bfs的基本思想是 首先訪問初始點v並將其標誌為已經訪問。接著通過鄰接關係將鄰接點入隊。然後每訪問過乙個頂點則出隊。按照順序,訪問每乙個頂點的所有未被訪問過的頂點直到所有的頂點均被訪問過。廣度優先遍歷類似與層次遍歷。其特點是盡可能先對橫向進行搜尋,從指的出發點,按照該點的路徑長度由短到長的順序訪問圖...

廣搜的優化技巧

一 雙向佇列bfs 首先乙個很神奇的小乾貨 雙端對列duque!雙端佇列中的元素可以從兩端彈出 常用操作 感覺超級超級複雜 1 建構函式 deque 建立乙個空deque deque int nsize 建立乙個deque,元素個數為nsize deque int nsize,const t t 建...