最少轉彎
【問題描述】
給出一張地圖,這張地圖被分成 n*n 個方塊,任何不是平地就是高山。平地可以通過,高山則不能。你在這張地圖上行走時,只能沿水平方向和垂直方向行進。
現在給出這張地圖的構成,請你計算從出發方塊到目標方塊需要的最少拐彎次數。拐彎次數等於行進方向的改變次數。例如下圖的行進路線,拐彎次數為5。
【輸入格式】
第1行為整數 n,表示地圖的尺寸。
接下來的 n 行,每行包含 n 個字元,第i行第j列的字元為’.’,表示該格子為平地,若為’x’,表示該格子為高山,若為’A’,表示你的起點,若為’B’,表示你的終點,字元間用一個空格分開。
注意,保證輸入合法,且只有一個’A’和一個’B’出現在地圖中。
【輸出格式】
一個整數,表示從A到B的最少的拐彎次數,如果A到B沒有路徑,則輸出-1。
【輸入樣例】
7
x . A . . x B
. . x . x . .
. . . . x . x
. x x . . . .
. . . . x x .
. . . . . . .
x x . . x . .
【輸出樣例】
5
【資料範圍】
1<=n<=100
題目大意:給出一個n*n的矩陣迷宮,迷宮上有一些障礙格子不能通過,現在要求從一點到另一個點的一條路徑,使得轉彎次數最小。
一開始想到搜尋,從找到的起點出發,每次都有兩類選擇:
1.向目前面對的方向前進一格(轉彎次數不變).
2.在這個格子轉彎(轉彎次數變大)
其中選擇2有3個小類
a.向左轉(轉彎次數+1)
b.向右轉(同上)
c.向後調頭(轉彎次數+2)
故設run(x,y,dir,d)深搜,時間複雜度4^n,n=100的情況不行啊(太無腦,不貼)
受上面狀態轉移的選擇的啟發:
設三元組d[x][y][dir]表示從起點到達(x,y)時面向dir方向的最小轉彎次數。
將整個迷宮看作無向帶權圖,用dijkstra或者SPFA就可以求出最小轉彎次數。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#define maxn 105
#define inf 1000000010
using namespace std;
int n;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
char mat[2*maxn][2*maxn];
int a[maxn][maxn],d[maxn][maxn][4];
struct data
{
int x,y,d,dir;
friend bool operator<(data a,data b)
{
return a.d>b.d;
}
};
int calc(int x,int y,int f,int nx,int ny,int e)
{
int t=1;//左右轉
if(f==e)return 0;//前進
if(f==0 && e==2)return 2;//調頭
if(f==1 && e==3)return 2;
if(f==2 && e==0)return 2;
if(f==3 && e==1)return 2;
return t;
}
void dijkstra(int sx,int sy)
{
priority_queue<data>pq;
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<4;k++)d[i][j][k]=inf;
for(int k=0;k<4;k++)
pq.push((data){sx,sy,0,k});
while(!pq.empty())
{
data t=pq.top();pq.pop();
if(t.d > d[t.x][t.y][t.dir])continue;
for(int k=0;k<4;k++)
{
int nx=t.x+dx[k],ny=t.y+dy[k];
if(nx<1 || nx>n || ny<1 || ny>n)continue;
if(a[nx][ny]==1)continue;
int c=calc(t.x,t.y,t.dir,nx,ny,k);
if(d[nx][ny][k]>t.d+c)
{
d[nx][ny][k] = t.d+c;
pq.push((data){nx,ny,d[nx][ny][k],k});
}
}
}
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
memset(a,0,sizeof(a));
scanf("%d",&n);
getchar();
for(int i=0;i<n;i++)
gets(mat[i]);
int sx,sy,ex,ey;
for(int i=0;i<n;i++)
for(int j=0;j<=2*n;j++)
{
if(mat[i][j]=='x')a[i+1][j/2+1]=1;
else if(mat[i][j]=='A')sx=i+1,sy=j/2+1;
else if(mat[i][j]=='B')ex=i+1,ey=j/2+1;
}
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",a[i][j]);
printf("\n");
}*/
dijkstra(sx,sy);
int ans=inf;
for(int k=0;k<4;k++)
{
ans=min(ans,d[ex][ey][k]);
}
if(ans<inf)printf("%d\n",ans);
else printf("-1\n");
return 0;
}
相關推薦
【Codeforces Round 323 (Div 2)B】【貪心】Robot's Task 最少轉彎次數拿走所有物品
Note In the first sample you can assemble all the pieces of information in the optimal manner by assembling first the piece of information in the first c
基礎搜尋題 最少轉彎問題
給出一張地圖,這張地圖被分為n×m(n,m<=100)個方塊,任何一個方塊不是平地就是高山。平地可以通過,高山則不能。現在你處在地圖的(x1,y1)這塊平地,問:你至少需要拐幾個彎才能到達目的地(x2,y2)?你只能沿著水平和垂直方向的平地上行進,拐彎次數就等於行進方向的改變(從水平到垂直或從垂直到水平
最少轉彎問題
Problem Description 給出一張地圖,這張地圖被分為n*m(n,m<=100)個方塊,任何一個方塊不是平地就是高山。平地可以通過,高山則不能。現在你處在地圖的(x1,y1)這塊平地,問:你至少需要轉幾個彎才能到達目的地(x2,y2)?你只能沿著水平
最少轉彎
【問題描述】 給出一張地圖,這張地圖被分成 n*n 個方塊,任何不是平地就是高山。平地可以通過,高山則不能。你在這張地圖上行走時,只能沿水平方向和垂直方向行進。 現在給出這張地圖的構成,請你計算從出發方塊到目標方塊需要的最少拐彎次數。拐彎次數等於
ArcGIS 網絡分析[4] 網絡數據集深入淺出之連通性、網絡數據集的屬性及轉彎要素
我只 三方 功能 如何使用 網絡數據 block 性問題 網絡 屬性 前面介紹完了如何創建網絡數據集、如何使用網絡分析功能,當然還有的讀者會迷惑於一些更深層次的問題,比如網絡數據集的連通性問題等。 因為不可能面面俱到,我只能挑重點來闡述,我覺得網絡數據集的連通性、屬性和轉
以最少的代碼讓自定的model實現NSCoding、NSCopying協議
key bject 根據 方法 conf imp oid 自定義 code 項目中用到了自定義的model:Person(栗子)。此model需要可以實現歸檔的功能,但是屬性非常多,且類似的model很多。如果按照常規去寫歸檔的代碼,那麽無論是寫起來還是維護起來都非常困難。
POJ 3177--Redundant Paths【無向圖添加最少的邊成為邊雙連通圖 && tarjan求ebc && 縮點構造縮點樹】
when tab sub exp 無向圖 redundant -m term 一個點 Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submis
hdoj 1257最少攔截系統
ont pop popu main 不能 post tdi div -s /*最少攔截系統 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768
最少錢幣數:
tint string ann new 2個 lastindex align sub 字符串 最少錢幣數 【問題描述】 這是一個古老而又經典的問題。用給定的幾種錢幣湊成某個錢數,一般而言有多種方式。例如:給定了6種錢幣面值為2、5、10、20、50、100,用來湊 15元,
hdu4612 無向圖中隨意加入一條邊後使橋的數量最少 / 無向圖縮點+求樹的直徑
child iostream tracking amp min esp _id 矛盾 cstring 題意如上,含有重邊(重邊的話,倆個點就能夠構成了邊雙連通)。 先縮點成樹,在求數的直徑,最遠的連起來,剩下邊(橋)的自然最少。這裏學習了樹的直徑求法:第一次選隨意
最少攔截系統-貪心或最長上升子序列
這樣的 cor wrap action pad mem format 貪心算法 string 最少攔截系統 Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I
算法基礎:刪除字符串中出現次數最少的字符(Golang實現)
cfb 出現次數 英文字母 clas har str 長度 == tracking 描寫敘述: 實現刪除字符串中出現次數最少的字符。若多個字符出現次數一樣,則都刪除。輸出刪除這些單詞後的字符串。 字符串中其他字符保持原來的順序。 輸入: 字符串僅僅包括小
HDU 1257 最少攔截系統 簡單DP
容易 target ++ font put 題目 ssi pre 路徑 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1257 題目大意:求有多少個單調非遞增序列。 解題思路:經典題的變形----LIS。可以按照題意,多次dp
換錢最少貨幣數
integer != font -1 length val 組成 ati 代碼 給定數組arr,arr中所有的值都為正數且不重復。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,在給定一個整數aim代表要找的錢數,求組成aim的最少貨幣數。 代碼: public
BZOJ 1633 [Usaco2007 Feb]The Cow Lexicon 牛的詞典:dp【刪字符最少】
小數 暴力 using 復雜 letter www 主串 blog 詞典 題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1633 題意: 給你一個長度為n的主串a,和一個有m個字符串s[i]的單詞書(s[i].
HDU1257 最少攔截系統 —— 貪心 or LIS(最長上升子序列)
ret pre key ear out hide 裏來 程序 http 題目鏈接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1257 最少攔截系統 Time Limit: 2000/1000 MS (Java/Oth
洛谷P1649 [USACO07OCT]障礙路線Obstacle Course BFS 最小轉彎
cst ace inline visit == char col d+ node 洛谷P1649 [USACO07OCT]障礙路線Obstacle Course BFS 最小轉彎 1 #include <cstdio> 2 #include &l
設計一個程序,有一個虛擬存儲區和內存工作區,實現下述三種算法中的任意兩種,計算訪問命中率(命中率=1-頁面失效次數/頁地址流長度)。附加要求:能夠顯示頁面置換過程。算法包括:先進先出的算法(FIFO)、最少使用算法(LFU)、最近未使用算法(NUR)
== oat 程序 表示 隊列 ini ++ 等待 進程 第一部分。。。 #include <cstdlib>#include<conio.h> #include<stdio.h>#include<stdlib.h>#incl
【轉】編寫高質量代碼改善C#程序的157個建議——建議152:最少,甚至是不要註釋
bsp 高質量 態度 改變 有意 我們 價值 保持 一份 建議152:最少,甚至是不要註釋 以往,我們在代碼中不寫上幾行註釋,就會被認為是鐘不負責任的態度。現在,這種觀點正在改變。試想,如果我們所有的命名全部采用有意義的單詞或詞組,註釋還有多少存在的價值。 即便再詳細的
HihoCoder1643 : 最少換乘([Offer收割]編程練習賽37)
次數 pre 兩個 其中 公交車 bsp 註意 pos post 描述 小Ho居住的城市有N條公交車線路,其中第i條線路上有Ki個車站。 某些線路之間會有公共的車站,小Ho可以在這些車站從一條線路換乘到另一條線路。 現在給定N條公交車線路以及兩個車站S和E