“科大訊飛杯”第十七屆同濟大學程序設計預選賽 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次就過了,還是很開心的,哈哈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章