zoukankan      html  css  js  c++  java
  • HDU 4026 Unlock the Cell Phone( 状态压缩 )

    题目链接~~>

    做题感悟:这题比赛的时候各种优化。可是都避免不了超时委屈,超时的时候应该想一下哪一个地方超时。哪个地方算多了,然后想方法去优化。

    解题思路:

                   首先说一个题NYOJ 878 格点这题是告诉你平面中两个格点(即整数点)。然后让你输出在这两点构成的直线上的全部格点。那怎么做呢 ?如果这两个格点为:x1 ,y1 ,x2 ,y2 .那么我们能够先求出 dx = x2 - x1 和 dy =  y2 - y1 的最大公约数 c ,然后让 dx / c ,dy/ c ,这样得到的就是格点之间的坐标的差,然后从 x1 ,y1 ,開始每次加这个差,一直出现等于 x1 = x2 且 y1 = y2 .

                   接下来分析这题:这题一看就知道是一个TSP的状态压缩,可是须要优化就是在推断两点的之间的格点的时候须要用到上面的格点思想,否则会超时,注意gcd要先预处理出来。

    代码:

    #include<iostream>
    #include<sstream>
    #include<map>
    #include<cmath>
    #include<fstream>
    #include<queue>
    #include<vector>
    #include<sstream>
    #include<cstring>
    #include<cstdio>
    #include<stack>
    #include<bitset>
    #include<ctime>
    #include<string>
    #include<cctype>
    #include<iomanip>
    #include<algorithm>
    using namespace std  ;
    #define INT __int64
    #define L(x)  (x * 2)
    #define R(x)  (x * 2 + 1)
    const int INF = 0x3f3f3f3f ;
    const double esp = 0.0000000001 ;
    const double PI = acos(-1.0) ;
    const INT mod =  1000000007 ;
    const int MY = 10 + 5 ;
    const int MX = 1<<(16) ;
    int num ,n ,m ;
    INT dp[MX][17] ;
    int g[6][6] ,gd[7][7] ,sta[30] ,key[20] ;
    int gcd(int a ,int b)
    {
        int r ;
        while(b)
        {
            r = a%b ;
            a = b ;
            b = r ;
        }
        return a ;
    }
    void init()
    {
        for(int i = 0 ;i <= 6 ; ++i)
          for(int j = i ;j <= 6 ; ++j)
            if(i == j)
                   gd[i][j] = i ;
            else
                   gd[i][j] = gd[j][i] = gcd(i ,j) ;
    }
    bool judge(int ri ,int rj ,int S) // 推断此条直线上是否存在不能走的点
    {    // 还原坐标
        int x1 = key[ri]/m ,y1 = key[ri]%m ,x2 = key[rj]/m ,y2 = key[rj]%m ;
        int dx = x2 - x1 ;
        int dy = y2 - y1 ;
        int gc = gd[abs(dx)][abs(dy)] ;
        dx = dx/gc ; dy = dy/gc ;
        while(true)
        {
            x1 += dx ; y1 += dy ;
            if(x1 == x2 && y1 == y2)  break ;
            if(g[x1][y1] == 1)   return false ;
            if(!g[x1][y1])
            {
                int temp = sta[x1*m + y1] ;
                if(!(S&(1<<temp)))   return false ;
            }
        }
        return true ;
    }
    void DP_SC()
    {
        memset(dp ,0 ,sizeof(dp)) ;
        for(int i = 0 ;i < num ; ++i)  // 初始化一个点的时候
              dp[1<<i][i] = 1 ;
        for(int S = 0 ; S < (1<<num) ; ++S)
          for(int i = 0 ; i < num ; ++i)
            if(dp[S][i])
            {
                for(int j = 0 ;j < num ; ++j)
                {
                    if(S&(1<<j))   continue ;
                    if(judge(i ,j ,S))
                        dp[S|(1<<j)][j] += dp[S][i] ;
                }
            }
        int S = (1<<num)-1 ;
        INT  ans = 0 ;
        for(int i = 0 ;i < num ; ++i)
           ans += dp[S][i] ;
        printf("%I64d
    " ,ans) ;
    }
    int main()
    {
        init() ;  // 初始化 GCD
        while(~scanf("%d%d" ,&n ,&m))
        {
            num = 0 ;  // 计算能够按的键的个数
            for(int i = 0 ;i < n ; ++i)
              for(int j = 0 ;j < m ; ++j)
              {
                  scanf("%d" ,&g[i][j]) ;
                  if(!g[i][j])      //   能够按的
                  {
                      key[num++] = i*m + j ;  // 记录坐标
                      sta[i*m + j] = num-1 ;  //记录其标号
                  }
              }
            DP_SC() ;
        }
        return 0 ;
    }
    
    

       

  • 相关阅读:
    矩阵按键转化为普通单个按键
    表达式位长 对结果的影响
    LuoguP3674 小清新人渣的本愿 && BZOJ4810: [Ynoi2017]由乃的玉米田
    BZOJ2956: 模积和
    NOIP2016 天天爱跑步
    LuoguP3948 数据结构
    AT2442 フェーン現象 (Foehn Phenomena)
    博客园美化笔记
    BZOJ2242: [SDOI2011]计算器
    分块入门与分块的经典应用
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6884041.html
Copyright © 2011-2022 走看看