日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P4011 孤岛营救问题

發布時間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4011 孤岛营救问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P4011 孤島營救問題

文章目錄

  • 輸入輸出樣例
  • 題意:
  • 題解:
    • 代碼:

輸入輸出樣例

輸入

4 4 9 9 1 2 1 3 2 1 2 2 2 0 2 1 2 2 0 2 1 3 1 0 2 3 3 3 0 2 4 3 4 1 3 2 3 3 0 3 3 4 3 0 4 3 4 4 0 2 2 1 2 4 2 1

輸出

14

題意:

(原題太長我就不貼了,簡單敘述一下)
一個N*M的迷宮,每個單元格之間可能有門或者墻,也可能啥也沒有。門和墻的總數為K(會讀入墻和門的位置坐標)
門存在種類,只有擁有對應種類的鑰匙才可以打開這類門
鑰匙的總量為S(會讀入鑰匙的坐標)
從一個單元格到另一個單元格時間為1
現在從左上角(1,1)出發,到右下角(N,M),最少花費多少時間?
針對樣例,看圖分析

紫色為鑰匙
橙色為墻或者門的種類
綠色為線路

題解:

這就是網絡流嗎?愛了愛了
迷宮的題一般用BFS就可以做
有了鑰匙我們就狀壓+BFS
狀態壓縮鑰匙,是為了方便記錄每一把鑰匙的狀態
就比如當前狀態是“100”,說明我有第三把鑰匙,因為第三位(從右往左)是1,而“100”對應的是4,你會發現你擁有第i把鑰匙,狀態就是2i-1(十進制下),這樣我們就可以用二進制來存儲鑰匙信息
key|=Key [ x ] [ y ] //就是將當前已有鑰匙的狀態給key
我們在開門時驗證自己有鑰匙的方式:
( mp [x] [y] [u.x] [u.y] & key ) ! = mp [x] [y] [u.x] [u.y]
[x][y]表示當前單元格,[u.x][u.y]表示上一個單元格
mp就表示兩個單元格之間門的編號,也可能是墻(表示方式和鑰匙一樣),直接與鑰匙&運算,如果運算后還是本身,說明有指定的鑰匙(因為有鑰匙說明那一位為1,1&1=1,還是本身,如果沒有指定鑰匙,說明那一位是0,0&1=0,值就發生改變)

然后就是bfs的走迷宮過程,走迷宮有四種狀態要continue
1.如果超格子了
2.如果撞墻了
3.如果遇到門但是木有鑰匙
4.之前走過了

坑點:
1.鑰匙可以重復使用而非用過即毀
2.一個地方可以存放多個鑰匙,所以保存鑰匙時不要將前一個覆蓋掉
3.初始點也可以放鑰匙
4.存在走不通的情況記得輸出-1

代碼:

代碼中注釋非常詳細

#include<bits/stdc++.h> using namespace std; const int dx[]={1,-1,0,0};//增量數組 const int dy[]={0,0,1,-1}; int vis[25][25][40005],x,y,xx,yy,p,pw[105],mp[16][16][16][16],Key[20][20],n,m,tot; struct nod{int x,y,key,stp;}q[5000005];//q為廣搜用的隊列 int bfs(){int h=1,t=1;vis[1][1][Key[1][1]]=1;//一開始就有位于(1,1)的鑰匙q[t]=(nod){1,1,Key[1][1],0};for(;h<=t;++h){nod u=q[h];//取隊頭for(int k=0;k<4;++k){int x=u.x+dx[k];int y=u.y+dy[k];int key=u.key;//已有鑰匙 int stp=u.stp;//已走步數 if(x<1||y<1||x>n||y>m)continue;//如果超出格子則跳過if(mp[x][y][u.x][u.y]==-1)continue;//如果兩個格子之間有墻則跳過if((mp[x][y][u.x][u.y]&key)!=mp[x][y][u.x][u.y])continue;//如果兩個格子之間有門而且手上所有的鑰匙里沒有能打開該門的鑰匙則跳過key|=Key[x][y];//更新已有鑰匙的情況 if(vis[x][y][key])continue;//如果之前搜到過這個狀態則跳過vis[x][y][key]=1;stp++;//可以則擴展q[++t]=(nod){x,y,key,stp};//保存當前坐標,以及鑰匙與步伐情況 if(x==n&&y==m)return stp;//如果已經走到(n,m)則返回答案}}return -1;//無法抵達 } int main(){pw[1]=1;for(int i=2;i<=15;++i)pw[i]=pw[i-1]<<1;//預處理pw數組scanf("%d%d%d",&n,&m,&p);scanf("%d",&tot);while(tot--){scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&p);if(p==0){mp[x][y][xx][yy]=mp[xx][yy][x][y]=-1;}else {mp[x][y][xx][yy]=mp[xx][yy][x][y]=pw[p];//將門的標號更新到指定位置 }}int q; scanf("%d",&tot);while(tot--){scanf("%d%d%d",&x,&y,&q);Key[x][y]|=pw[q];//表示在(x,y)點上有編號為q的鑰匙,將鑰匙的編號更新到指定坐標 }cout<<bfs();return 0; }

這個題我就用兩個字形容:絕了
很久沒有遇到這么好的題

總結

以上是生活随笔為你收集整理的P4011 孤岛营救问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。