“科大讯飞杯”第十七届同济大学程序设计预选赛 D题 车辆调度【DFS+剪枝】

题目链接: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次就过了,还是很开心的,哈哈。

猜你喜欢

转载自blog.csdn.net/ljw_study_in_CSDN/article/details/106044432