題目鏈接:https://ac.nowcoder.com/acm/contest/5477/D
思路
首先,這題的數據範圍是非常小的,都是10以內的。所以可以直接暴力,具體就是用DFS暴力(遞歸)。
那麼關鍵就是寫DFS函數,每次的DFS就是一個狀態,每個狀態就是一個圖,然後我們在當前狀態裏遍歷每個小車的位置,然後對於每個小車,進行4個方向的搜索,直到撞到障礙物就停下來,更新R(障礙物)的位置和障礙物標記,搜索完之後再還原位置和標記(回溯)。
遍歷方向的時候可以剪枝,不是每次都要搜四個方向,因爲如果上次是右方向撞到了障礙物,那麼這次就不用再搜右方向了,只要搜剩下三個方向就行(最開始的車當然還是要搜四個方向)。
AC代碼
#include <bits/stdc++.h>
using namespace std;
const int N=15;
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int ans=0;//找到可行方案後ans置爲1
int n,m,k,num;
bool vis[N][N];//標記(i,j)位置是否是障礙物
char mp[N][N];
struct node
{
int x,y;
}a[N*N];//存小車的位置
void dfs(int cnt,int pred)
//cnt表示當前搜索到狀態的時間,pred表示上次進來的方向
{
if(ans==1||cnt>k)return;
for(int p=1;p<=num;p++)//車的編號
{
int x=a[p].x;
int y=a[p].y;
for(int i=0;i<4;i++)//找一個能走的方向
{
if(i==pred)continue;//剪枝優化
//不再按上一次的方向搜索(否則浪費時間)
for(int j=0;;j++)//在這個方向上能移動的格數
{
int nx=x+(j+1)*dir[i][0];
int ny=y+(j+1)*dir[i][1];
if(nx<1||nx>n||ny<1||ny>m||vis[nx][ny])//撞牆
{
int tx=x+j*dir[i][0];
int ty=y+j*dir[i][1];
//撞牆前的最後一個位置,即新"R"的位置是(tx,ty)
if(mp[tx][ty]=='D'&&cnt+1==k)//注意是cnt+1
{
ans=1;
return;//找到可行解,結束
}
vis[x][y]=0;
vis[tx][ty]=1;//移動被擋住的標記
a[p].x=tx;
a[p].y=ty;//移動第p個小車的位置
dfs(cnt+1,i);
vis[tx][ty]=0;
vis[x][y]=1;//回溯標記
a[p].x=x;
a[p].y=y;//回溯位置
break;//這個方向不用再移動了,找下一個方向搜索
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>m>>n>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='R')
{
a[++num]={i,j};
vis[i][j]=1;
}
if(mp[i][j]=='X')vis[i][j]=1;
}
if(num==0)printf("NO\n");
else
{
dfs(0,-1);
if(ans)printf("YES\n");
else printf("NO\n");
}
return 0;
}
這題比賽的時候寫了兩百行,然後還wa了,主要原因是思路不清晰,平時DFS函數寫得少,代碼功底不夠啊。
補題的時候,重寫了一遍代碼,交了2次就過了,還是很開心的,哈哈。