zoukankan      html  css  js  c++  java
  • SGU 125 Shtirlits 搜索+可行性剪枝

    500ms时限406ms水过……

    直接枚举肯定超时,需要剪枝。

    枚举每个格子的元素,检查其左上角和正上方格子是否满足条件,若不满足不必再向下搜索。

    这里 看到一个更好的方法: 枚举每个格子是哪个相邻的比它大。然后DFS看看有没有环。这样的复杂度只有(2^5*3^5)。

    不过我没写出来……而且也不太清楚这个时间复杂度是怎么算的……求指点!

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 
      5 const int dx[] = { -1, 1, 0, 0 };
      6 const int dy[] = { 0, 0, -1, 1 };
      7 
      8 int N;
      9 int mat[5][5];
     10 int G[5][5];
     11 
     12 bool check( int i, int j )
     13 {
     14     return i >= 0 && i < N && j >= 0 && j < N;
     15 }
     16 
     17 //wh=true 代表检查左上角格子是否满足条件, wh=false代表检查正上方格子
     18 bool ok( int x, int y, bool wh )
     19 {
     20     int cnt = 0;
     21     for ( int k = 0; k < 4; ++k )
     22     {
     23         int xx = x + dx[k];
     24         int yy = y + dy[k];
     25         if ( check( xx, yy ) && G[xx][yy] > G[x][y] ) ++cnt;
     26     }
     27 
     28     if ( wh ) return cnt == mat[x][y];
     29     return cnt <= mat[x][y];
     30 }
     31 
     32 bool Judge()
     33 {
     34     int cnt = 0;
     35 
     36     for ( int i = 0; i < N; ++i )
     37     {
     38         for ( int j = 0; j < N; ++j )
     39         {
     40             cnt = 0;
     41             for ( int k = 0; k < 4; ++k )
     42             {
     43                 int xx = i + dx[k];
     44                 int yy = j + dy[k];
     45                 if ( check( xx, yy ) )
     46                 {
     47                     if ( G[xx][yy] > G[i][j] )
     48                         ++cnt;
     49                 }
     50             }
     51             if ( cnt != mat[i][j] ) return false;
     52         }
     53     }
     54 
     55     return true;
     56 }
     57 
     58 bool DFS( int cur )
     59 {
     60     if ( cur == N * N )
     61     {
     62         if ( Judge() ) return true;
     63         return false;
     64     }
     65 
     66     int x = cur / N;
     67     int y = cur % N;
     68     for ( int i = 0; i < 10; ++i )
     69     {
     70         G[x][y] = i;
     71 
     72         bool okey = true;
     73 
     74         if ( check( x - 1, y - 1 ) )
     75         {
     76             if ( !ok( x - 1, y - 1, true ) )
     77                 okey = false;
     78         }
     79 
     80         if ( okey && check( x - 1, y ) )
     81         {
     82             if ( !ok( x - 1, y, false ) )
     83                 okey = false;
     84         }
     85 
     86         if ( okey )
     87         {
     88             if ( DFS( cur + 1 ) )
     89                 return true;
     90         }
     91 
     92         G[x][y] = -1;
     93     }
     94 
     95     return false;
     96 }
     97 
     98 int main()
     99 {
    100     //freopen( "s.out", "w", stdout );
    101     while ( scanf( "%d", &N ) == 1 )
    102     {
    103         for( int i = 0; i < N; ++i )
    104             for( int j = 0; j < N; ++j )
    105                 scanf( "%d", &mat[i][j] );
    106 
    107         memset( G, -1, sizeof( G ) );
    108         if ( DFS( 0 ) )
    109         {
    110             for ( int i = 0; i < N; ++i )
    111             {
    112                 for ( int j = 0; j < N; ++j )
    113                 {
    114                     if ( j ) putchar(' ');
    115                     printf( "%d", G[i][j] );
    116                 }
    117                 puts("");
    118             }
    119         }
    120         else puts("NO SOLUTION");
    121     }
    122     return 0;
    123 }
  • 相关阅读:
    最快效率求出乱序数组中第k小的数
    调整数组顺序使奇数位于偶数前面
    分治算法的完美使用----归并排序
    快速排序分区以及优化方法
    分治法以及快速排序
    高效求a的n次幂的算法
    最长连续递增子序列(部分有序)
    在有空字符串的有序字符串数组中查找
    旋转数组的最小数字(改造二分法)
    递归----小白上楼梯
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3215281.html
Copyright © 2011-2022 走看看