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\n" ,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 ;
}
时间: 2024-10-10 22:40:37

HDU 4026 Unlock the Cell Phone( 状态压缩 )的相关文章

HDU 4026 Unlock the Cell Phone(动态规划)

Unlock the Cell Phone Problem Description Modern high-tech cell phones use unlock patterns to unlock the system. The pattern is usually a 3*3 dot array. By moving your finger over there dots, you can generate your personal unlock pattern. More specif

HDU 4640 Island and study-sister(状态压缩)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640 题意:给出一个无向图,边有权值.三个人初始时呆在1号点.在其余n-1个点中有些点要求被遍历到.且除了1号点之外每个点最多只能被一个人遍历.求要求被遍历的点中最后被遍历的点的最小时刻. 思路:用f[st][i]表示一个人遍历完集合st最后停在i的最小时间,之后用f[st][i]得到f1[st],表示遍历完集合st的最小时间.然后得到dp[i][st]表示i个人遍历完st的最小时间. int g[

HDU 3001 Travelling (三进制状态压缩 DP)

题意:有 n 个city,可以选择任一城市作为起点,每个城市不能访问超过2次, 城市之间有权值,问访问全部n个城市需要的最小权值. 思路:因为每个城市可以访问最多两次,所以用三进制表示访问的状态. 详细见代码注释!!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath> #inclu

[ACM] HDU 1400 Mondriaan&#39;s Dream (状态压缩,长2宽1长方形铺满)

Mondriaan's Dream Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 783    Accepted Submission(s): 506 Problem Description Squares and rectangles fascinated the famous Dutch painter Piet Mondri

HDU 5418 Victor and World (状态压缩dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 题目大意:有n个结点m条边(有边权)组成的一张连通图(n <16, m<100000).求从第一个点出发,经过每个点至少一次后回到原点的最小路径边权和. 分析:发现我还真是菜. n<16,很明显的状态压缩标记,先将所有点的编号减去1,使其从0开始编号.dp[i][j]表示从0号点出发,当前状态为i (二进制位为1表示对应点已走过,否则没走过), 当前位置为 j,  回到原点的最小代价,

HDU 6607 Time To Get Up(状态压缩+枚举)

题目网址: http://acm.hdu.edu.cn/showproblem.php?pid=6077 思路: 先预处理一下,将每个数字块的"X"看作1,"."看作0,进行状态压缩转换成二进制数,用数组保存.再遍历每个块点的元素,枚举0-9看是否符合当前位数. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 typedef long long l

HDU 5418——Victor and World——————【状态压缩+floyd】

Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 891    Accepted Submission(s): 399 Problem Description After trying hard for many years, Victor has finally received a pilot li

[ACM] HDU 5025 Saving Tang Monk (状态压缩,BFS)

Saving Tang Monk Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 941    Accepted Submission(s): 352 Problem Description <Journey to the West>(also <Monkey>) is one of the Four Great Clas

HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由于得到每张卡片的状态不知道,所以用状态压缩,dp[i] 表示这个状态时,要全部收齐卡片的期望. 由于有可能是什么也没有,所以我们要特殊判断一下.然后就和剩下的就简单了. 另一个方法就是状态压缩+容斥,同样每个状态表示收集的状态,由于每张卡都是独立,所以,每个卡片的期望就是1.0/p,然后要做的就是要去重,既然