zoukankan      html  css  js  c++  java
  • 11H:迷宫入口

    总时间限制: 
    1000ms
     
    内存限制: 
    10000kB
    描述

    爱好探险的你,找到一座装满了宝藏的迷宫的入口,你看到入口的大门上有一个边长为s的正方形的大锁,旁边散落着n块正方形的金属小片,你意识到锁的钥匙,即是用这n小块,拼成大门上的正方形,你想知道是否能拼成这把钥匙打开迷宫的大门。

    输入
    输入包含多组数组,第一行是一个整数t(1 <= t <= 10),表示有t组数据。接下里每组数组包含整数s,即锁的边长,整数n(1 <= n <= 16),即金属小片的数量,接下来n个整数,分别是各个小片的边长ci(1 <= ci <= 10)。
    输出
    每组数据输出一行,输出“YES"或者"NO",表示是否可以打开大门。
    样例输入
    2
    4 8 1 1 1 1 1 3 1 1
    5 6 3 3 2 1 1 1
    
    样例输出
    YES
    NO
     1 #include <iostream>
     2 #include <vector>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 int a[15];
     7 int c[17];
     8 int m[45][45];
     9 int s, n;
    10 void fill(int x, int y, int L, int vol){ //以(x,y)左上角填充内容为vol的正方形 
    11     for(int i = x; i < x+L; i++)
    12         for(int j = y; j < y+L; j++) 
    13             m[i][j] = vol;
    14 }
    15 bool dfs(int x,int y){
    16     if(m[x][y]){
    17         if(y==s-1){
    18             if(x==s-1)return 1;
    19             else return dfs(x+1,0);    
    20         }
    21         else return dfs(x,y+1);
    22     }
    23     bool ret=0;
    24     for(int L=1;!ret;L++){
    25         if(y+L>s||x+L>s||m[x][y+L-1])break;
    26         if(!c[L])continue;
    27         c[L]--;
    28         fill(x,y,L,1);
    29         ret|=dfs(x,y);
    30         fill(x,y,L,0);
    31         c[L]++;
    32     }
    33     return ret;
    34 }
    35 
    36 int main(){
    37     int t;
    38     cin>>t;
    39     while(t--){
    40         cin>>s>>n;
    41         memset(a, 0, sizeof(a));
    42         memset(c, 0, sizeof(c));
    43         memset(m, 0, sizeof(m));
    44         for(int i = 1; i <= n; i++){
    45             cin>>a[i];
    46             c[a[i]] ++;
    47         }
    48         if(s>40){
    49             cout<<"NO"<<endl;
    50             return 0;
    51         }
    52         bool ans = dfs(0, 0);
    53         if(ans) cout<<"YES"<<endl;
    54         else cout<<"NO"<<endl;
    55     }
    56     return 0;
    57 }

    备注:这差不多也就是标答,这么暴力居然也可以过orz 另外我怀疑这道题数据范围写错了,因为l和c数组开到40+才能过。开小了就是WA问了助教,等待答复中。。

    大于四十不可能是因为,16个片,每个边长最大为10(这么看数据范围又没错?),加在一起面积也就是1600,也就是说锁的边长大于40就不可能凑出来了。当然不写这个也可以AC。

    然后这个dfs的写法就 非常神奇……从左上角开始填充,先填充到最右,然后换行。标黄的地方我还是没太明白,wsl。我明白了。

    因为前面说的填充顺序的问题,这时候填完了第一行的正方形,该填第二行了。这时候边长是从小往大尝试的,这很重要,所以x+L或者y+L出界了肯定不行要break这是显然的;还有就是如果像途中虚线正方形一样,如果它右上角已经开始侵占了第一行的正方形的位置(之前填充过)也说明边长太大了,要break。

    为啥这么难。


    这个dfs也可以不这么写,用更常规的方法是这样的:

     1 #include <iostream>
     2 #include <vector>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 int a[45];
     7 int c[45];
     8 int m[45][45];
     9 int s, n;
    10 void fill(int x, int y, int L, int vol){ //以(x,y)左上角填充内容为vol的正方形
    11     for(int i = x; i < x+L; i++)
    12         for(int j = y; j < y+L; j++)
    13             m[i][j] = vol;
    14 }
    15 bool dfs(int x,int y){
    16     if(m[x][y]){
    17         if(y==s-1){
    18             if(x==s-1)return 1;
    19             else return dfs(x+1,0);
    20         }
    21         else return dfs(x,y+1);
    22     }
    23     //bool ret=0;
    24     for(int L=1;;L++){
    25         if(y+L>s||x+L>s||m[x][y+L-1])break;
    26         if(!c[L])continue;
    27         c[L]--;
    28         fill(x,y,L,1);
    29         if(dfs(x,y)) return true;
    30    //     ret|=dfs(x,y);
    31         fill(x,y,L,0);
    32         c[L]++;
    33     }
    34     return false;
    35 }
    36 
    37 int main(){
    38     int t;
    39     cin>>t;
    40     while(t--){
    41         cin>>s>>n;
    42         memset(a, 0, sizeof(a));
    43         memset(c, 0, sizeof(c));
    44         memset(m, 0, sizeof(m));
    45         for(int i = 1; i <= n; i++){
    46             cin>>a[i];
    47             c[a[i]] ++;
    48         }
    49         if(s>40){
    50             cout<<"NO"<<endl;
    51             return 0;
    52         }
    53         bool ans = dfs(0, 0);
    54         if(ans) cout<<"YES"<<endl;
    55         else cout<<"NO"<<endl;
    56     }
    57     return 0;
    58 }
  • 相关阅读:
    Go笔记
    EFCore CodeFirst操作MySQL
    基于NET Core简单操作Kafka
    NETCore2.2/3.0+使用带有权限验证的Swagger
    Net操作RabbitMQ
    Mysql报错问题汇总
    GDSM自动化部署shell脚本
    NET操作Redis
    ViewState原理
    使用jsonp跨域请求
  • 原文地址:https://www.cnblogs.com/fangziyuan/p/13150020.html
Copyright © 2011-2022 走看看