Bootstrap

[蓝桥杯]路径之谜

题目链接

题意

给定 n × n n\times n n×n 的地图
从左上角走到右下角 四联通方向 每走到一个格子 向正北和正西射一支箭 每个点只能走一次

题目给出最后竖向和横向上的每个靶子上的箭的总数

题目保证路径唯一 求出行走路径
题目约定每个小格子用一个数字代表,从西北角开始编号: 0 , 1 , 2 , 3... 0,1,2,3 ... 0,1,2,3...

数据范围
0 < = N < = 20 0<=N<=20 0<=N<=20

思路

开col[N] row[N]数组记录当前每一行/列 上有多少只箭
设计 d f s ( i n t   x , i n t   y , i n t   i d x ) dfs(int \space x,int \space y,int \space idx) dfs(int x,int y,int idx)
x,y 表示上一个点的坐标 这一次dfs要通过(x,y)的四个方向扩展
idx表示上一次是第几步 (从0开始) 用于path数组记录 填充和撤销
(我一开始没开idx这一维,回溯用pop_back 这样没法正确撤销选择)

dfs枚举所有方案 如果可行 就输出答案

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);}
void cmin(int &a,int b){a=min(a,b);}
const int N=100,MOD=1e9+7,INF=0x3f3f3f3f,LINF=LLONG_MAX;
int a[N],b[N],col[N],row[N],n;
bool vis[N][N];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
vector<int>path(500,-1);

void dfs(int x,int y,int idx){
    if(x==n-1&&y==n-1) {
        for(int i=0;i<n;i++){
            if(col[i]!=a[i]||row[i]!=b[i]){
                return;
            }
        }
        for(int i=0;i<=idx;i++) cout<<path[i]<<' ';cout<<endl;
        return;
    }

    for(int i=0;i<4;i++){
        int tx=x+dx[i],ty=y+dy[i];
        if(tx<0||tx>=n||ty<0||ty>=n||vis[tx][ty]) continue;
        if(col[ty]==a[ty]&&row[tx]==b[tx]){
            continue;
        }

        col[ty]++,row[tx]++;
        if(col[ty]>a[ty]||row[tx]>b[tx]){
            col[ty]--,row[tx]--;
            continue;
        }
        vis[tx][ty]=1;
        path[idx+1]=tx*n+ty;
        dfs(tx,ty,idx+1);
        vis[tx][ty]=0;
        path[idx+1]=-1;
        col[ty]--,row[tx]--;
    }
}


void solve() {
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++) cin>>b[i];

    vis[0][0]=1;
    path[0]=0;
    col[0]++,row[0]++;
    dfs(0,0,0);
    // for(int i:path) cout<<i<<' ';cout<<endl;
}   

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int t=1;
    // cin>>t;
    while (t--) solve();

}

细节

if(x==n-1&&y==n-1) {
    for(int i=0;i<n;i++){
        if(col[i]!=a[i]||row[i]!=b[i]){
            return;
        }
    }
    for(int i=0;i<=idx;i++) cout<<path[i]<<' ';cout<<endl;
    return;
}

这段代码注意要在x==-1&&y==n-1 时return
因为x,y代表上一次走的点 既然上一次已经走到右下角了 就不要继续往下走了

另外 要判断每个行列的箭数目是否匹配 如果匹配才要输出path

;