zoukankan      html  css  js  c++  java
  • 【上海交大oj】畅畅的牙签袋(改)(枚举+模拟)

    题目描述

    上次妄图遮掩显示器的企图失败了,所以畅畅很不开心。这次,他换了一种牙签袋卷土重来了。这次他选择了十字形的牙签袋(即每贴一个牙签袋都会影响5块区域,贴的时候中心点必须贴在显示器上,如果中心点在边上,则会有一些块暴露在显示器外,不过没关系,畅畅会把这些块剪掉的),所以他觉得这次一定能把整个显示器贴的满满的。

    贴了又撕,撕了又贴,怔了一会儿后,他发现整个显示器被整的凹凸不平,非常难受。因为强迫症,他决定要把每一块区域都贴到有偶数层牙签袋(就是说这次可以重叠的铺了),而他现在想知道他最少需要多少牙签袋才能做到。

    还是因为那个原因,这个活就是你们的了。

    输入格式

    输入第一行有两个整数,H和W(1<=H,W<=16),代表显示器大小。

    接下来有H行,每行W个整数L(0<=L<=10000),代表每个区域已有的牙签袋层数。

    输出格式

    输出最少所需的牙签袋数目,若无论如何都无法完成要求,则输出-1.

    Sample Input1

    1 2
    0 1
    

    Sample Output1

    -1
    

    Sample Input2

    2 2
    0 1
    2 3
    

    Sample Output2

    2


    考试的时候思维定势了,以为又是动归,但是看起来好麻烦,于是就没有勇气尝试,实在不该。实际上这题就是要用暴力求解,可以发现,当上一行的状态确定的时候,下一行有唯一解,也就是上一行为单数的这一行必须要铺才可以,那么我们只需枚举第一行的所有状态,看一看这个状态下模拟下来能不能达到要求,找到一个最小的就好了,枚举第一行可以写一个w重的循环,也可以递归(dfs),或者直接用压缩的状态(二进制)枚举,模拟就是一行一行根据上一行的状态改变这一行和下一行的状态。

    代码:
     1 #include <iostream>
     2 using namespace std;
     3 
     4 int begin[16][16];
     5 int nowline[16];
     6 int nextline[16];
     7 int lastline[16];
     8 int main(){
     9     int h,w,min = 9999999;
    10     
    11     cin>>h>>w;
    12     for (int i = 0;i < h;++i) 
    13         for (int j = 0;j < w;++j) cin>>begin[i][j];
    14 
    15     if (h==1){
    16         int i,cnt = 0;
    17         for (i = 0;i < w;++i) if (begin[0][i] & 1){
    18             if (i+1 < w) begin[0][i+1]++;
    19             if (i+2 < w) begin[0][i+2]++;
    20             cnt++;
    21         }
    22         if (begin[0][w-1] & 1) cout<<-1<<endl;
    23         else cout<<cnt<<endl;
    24         return 0;
    25     }
    26     for (int i = 0;i < 1<<w;++i){ //枚举第一行 
    27      
    28         for (int j = 0;j < w;++j) {  //初始化 
    29              nowline[j] = begin[0][j];
    30              nextline[j] = begin[1][j];
    31         }//for (int j = 0;j < w;++j) cout<<nowline[j]<<' ';cout<<endl;
    32         // for (int j = 0;j < w;++j) cout<<nextline[j]<<' ';cout<<endl;
    33         int t = 1,cnt = 0;
    34          for (int j = 0;j < w;++j,t<<=1){
    35              if (i & t){
    36                  nextline[j]++;
    37                  nowline[j]++;
    38                  if (j > 0) nowline[j-1]++;
    39                  if (j<w-1) nowline[j+1]++;
    40                  cnt++;
    41              }
    42         }
    43         
    44         for (int j = 1;j < h-1;j++){ //开始模拟 
    45             for (int k = 0;k < w;++k){
    46                 lastline[k] = nowline[k];
    47                 nowline[k] = nextline[k];
    48                 nextline[k] = begin[j+1][k];
    49             }
    50             for (int k = 0;k < w;++k){
    51                 if (lastline[k] & 1){
    52                     nextline[k]++;
    53                     nowline[k]++;
    54                     if (k>0) nowline[k-1]++;
    55                     if (k<w-1) nowline[k+1]++;
    56                     cnt++;
    57                 }
    58             }
    59         }
    60         //处理倒数第二行 
    61         for (int j = 0;j < w;++j) if (nowline[j] & 1) {
    62             nextline[j]++;
    63             if (j>0) nextline[j-1]++;
    64             if (j< w-1) nextline[j+1]++;
    65             cnt++;
    66         }
    67         //判断是否可行 
    68         int j = 0;
    69         for (j = 0;j < w;++j){
    70             if (nextline[j] & 1) {
    71                 break;
    72             }
    73         }
    74         if (j==w && cnt<min) {min = cnt;}
    75      }
    76      
    77      if (min < 9999999) cout<<min<<endl;
    78      else cout<<-1<<endl;
    79     
    80     return 0;
    81 }
    View Code
  • 相关阅读:
    288.软件开发过程与软件测试
    287.软件测试概述
    离散数学课程重点
    博客园美化
    渗透测试-Getshell总结
    C++迭代器
    每日一题2
    计算机网络面试总结(传输层)
    每日一题-1
    网络安全必备技能
  • 原文地址:https://www.cnblogs.com/wenma/p/4655859.html
Copyright © 2011-2022 走看看