zoukankan      html  css  js  c++  java
  • 【牛客7872 H 德邦王国】dfs全排列跑图暴力冲过去

    【牛客7872 H 德邦王国】dfs全排列跑图暴力冲过去

    传送门

    题目描述

    ​ 在遥远的德邦草原,有一个古老的国度。
    ​ 这里的国王有一种特殊的能力,他可以在限定次数内互换自己和某些子民的位置
    ​ 现在国王需要让自己的子民排列成一个整齐的方阵接受检阅,但是他们的动作太慢了
    ​ 于是国王决定用自己的能力来完成剩余的排列,从而将自己的子民排列
    ​ 成能让他满意的样子。

    ​ 请你帮忙计算国王最少需要瞬间移动多少次,才能将方阵变成他想要的样子。
    ​ 注意国王不得移动出方阵,国王的瞬间移动方式将由输入数据给出。

    输入描述:

            N K M分别表示矩阵的大小、国王的瞬移方法数量和国王的瞬间移动限定次数 
            接下来 K 行 Xi Yi 表示国王可以让自己和 (X + Xi, Y + Yi)上的子民位置互换
            其中 X Y 表示国王当前的位置
            接下来 N 行为一个矩阵,表示当前的矩阵排列
            接下来 N 行为一个矩阵,表示能让国王满意的矩阵排列 
            
            矩阵仅由(0, 1, 2)组成,其中 0 表示女性子民,1 表示男性子民, 2 表示国王 
            
    
            1 <= N <= 5 
            1 <= K <= 8 
            1 <= M <= 15 
    

    输出描述:

             如果国王可以在限定次数内将矩阵变成他喜欢的样子,请你输出最小次数
             反之,请你输出 -1 
    

    输入

    3 2 1
    1 -1
    1 1
    1 0 0
    0 1 2
    0 1 1
    1 0 0 
    0 1 1
    0 2 1
    

    输出

    1
    

    说明

    位于坐标(2, 3)的国王和位于坐标(3, 2)的男性子民
    互换位置从而使得方阵变成了他喜欢的样子
    

    示例2

    输入

    3 1 1
    -1 0
    1 0 0
    0 1 2
    0 1 1
    1 0 0 
    0 1 1
    0 2 1
    

    输出

    -1
    

    说明

    此时国王只能往上移动,所以无法将方阵变成他喜欢的样子
    

    题意

    n*n的方阵,2代表国王,其余代表臣民。国王有k种移动方式,问国王能在限定的k步内让方阵的排布达到它想要的样子吗?

    题解

    直接暴力dfs,k种移动方式全排列跑过去,看最少多少步能让方阵达到目标方阵的样子。

    在每一次进入dfs,计算一下当前矩阵是否已经成为目标矩阵,如果已经成为目标矩阵就把当前步数和ans取个min。

    纯暴力还过不去,又T又MLE。

    • 爆栈了,所以递归层次不能太深,观察一下限定步数m的范围是<=15的,所以最多递归15层,到16的时候就不用递归下去了肯定不行,这是对爆栈的优化。
    • 再考虑,假设现在有t个臣民位置和目标方阵不符,那么最好的情况下(假设国王可以随意移动)都需要国王移动t步才能让所有臣民归位,国王每次都跟在目标方阵中应该在国王所在当前位置的臣民交换位置,这样全部归位就需要t步。那如果现在剩余的步数不足t步了,也可以直接结束递归,这是对时间复杂度的一点优化。

    这两个优化一加就可以冲过去啦!

    /****************************
    * Author : W.A.R            *
    * Date : 2020-11-04-19:13   *
    ****************************/
    /*
    */
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    #include<string>
    #include<set>
    #define IOS ios::sync_with_stdio(false)
    #define show(x) std:: cerr << #x << " = " << x << std::endl;
    #define mem(a,x) memset(a,x,sizeof(a))
    #define Rint register int
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+10;
    const int maxm=2e6+10;
    const ll mod=1e9+7;
    const double PI=acos(-1.0);
    const double eps=1e-7;
    int ans=16,X,Y,n,k,m,m1[100][100],m2[100][100],a[100],b[100];
    bool ok(int x,int y){return x>0&&x<=n&&y>0&&y<=n;}
    void dfs(int x,int y,int step){
    	int sum=0;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if(m1[i][j]==m2[i][j])sum++;
    		}
    	}
    	if(sum==n*n){ans=min(ans,step);return;}
    	if(step>=min(ans,m))return;
    	if(m-step<(n*n-sum))return;
    	for(int i=1;i<=k;i++){
    		int nx=x+a[i],ny=y+b[i];
    		if(ok(nx,ny)){
    			swap(m1[x][y],m1[nx][ny]);
    			dfs(nx,ny,step+1);
    			swap(m1[x][y],m1[nx][ny]);
    		}
    	}
    }
    int main(){
    	scanf("%d%d%d",&n,&k,&m);
    	for(int i=1;i<=k;i++)scanf("%d%d",&a[i],&b[i]);
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
    		scanf("%d",&m1[i][j]);
    		if(m1[i][j]==2)X=i,Y=j;
    	}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&m2[i][j]);
    	dfs(X,Y,0);
    	if(ans>m)printf("-1
    ");
    	else printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Sikuli:创新的图形化编程技术
    缺少对象 WScript 问题解决方法
    TD8.0迁移到QC9.2,自动迁移失败,手动迁移
    QTP使用小技巧
    外部VBS的调用
    mysql 发生系统错误1067的解决方法
    Mysql 本地计算机无法启动 mysql 服务 错误 1067:进程意外终
    windows下mysql忘记root密码的解决方法
    mysql 常用命令用法总结积木学院整理版
    java、c/c++ 、python 等性能比较 杂谈(整理)
  • 原文地址:https://www.cnblogs.com/wuanran/p/13927714.html
Copyright © 2011-2022 走看看