hdu 1067 Gap

  

    本来认为是个数学题或者dp题,但是后来看到规则发现用搜索完全可以做

    因为规则限制,每次只能把空白左边下一位的数移动到空白处,所以每次最多走4种情况,这就可以bfs了

    一开始用map的,但是TLE了(虽然不是这个问题)于是手写hash,对999991取了个余,虽然一定不完善,但是数据没那么强。

    手写hash后依旧TLE……最后检查了好几遍才发现是空格左边可能仍是空格,这一点没有考虑到,所以一直TLE(差点手写队列了o(╯□╰)o)

    加了个判断后,500ms就过了……

 

    注意位运算的优先级,今天被坑好几次了

 

/*
author:jxy
lang:C/C++
university:China,Xidian University
**If you need to reprint,please indicate the source**
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <map>
#define INF 1E9
using namespace std;
const char ss[32]={11,12,13,14,15,16,17,0,21,22,23,24,25,26,27,0,31,32,33,34,35,36,37,0,41,42,43,44,45,46,47,0};
string aim="";
struct node
{
    int x,y;
};
char m[4][8];
struct state
{
   node pos[50],blank[4];//pos确定每个数字位置,blank是4个空格位置
   string s;//图
   int lvl;//步数
};
string m2s()//把图变成字符串
{
    string now="";
    int i,j;
    for(i=0;i<4;i++)
     for(j=0;j<8;j++)
      now.push_back(m[i][j]);
    return now;
}
int get_hash(string s)//获得hash值
{
    long long ans=0;
    for(int i=0;i<32;i++)
        ans=(ans<<1)+s[i];
    return ans%999991;
}
bool vis[1000000];
queue<state> q;
state now,next;
node temp;
int bfs()
{
    memset(vis,0,sizeof(vis));
    while(!q.empty())q.pop();
    int i,j,t=0,k,o,lvl;
    for(i=0;i<4;i++)
     for(j=0;j<8;j++)
     {
         temp.x=i;temp.y=j;
         if(m[i][j]==0)now.blank[t++]=temp;
         else now.pos[m[i][j]]=temp;
     }
    now.s=m2s();vis[get_hash(now.s)]=1;
    now.lvl=1;
    q.push(now);
    int Aim=get_hash(aim);
    while(!q.empty()&&!vis[Aim])
    {
        now=q.front();q.pop();
        next=now;
        next.lvl=now.lvl+1;
        for(i=0;i<4;i++)
        {
            node &b=next.blank[i];
            o=8*b.x+b.y-1;
            t=next.s[o];
            if(t%10==7||t==0)continue;//注意空格旁还是空格的情况
            k=t+1;
            node &p=next.pos[k];
            k=p.x*8+p.y;
            o++;
            swap(next.s[o],next.s[k]);//移动位置
            t=get_hash(next.s);
            if(!vis[t])
            {
                if(t==Aim)return next.lvl-1;
                swap(p,b);
                q.push(next);
                vis[t]=1;
                swap(p,b);
            }
            swap(next.s[o],next.s[k]);//恢复
        }
    }
    return vis[Aim]-1;
}
int main()
{
   int T;
   for(T=0;T<32;T++)aim.push_back(ss[T]);
   scanf("%d",&T);
   while(T--)
   {
       memset(m,0,sizeof(m));
       int i,j,t;
       for(i=0;i<4;i++)
        for(j=1;j<8;j++)
        {
            scanf("%d",&t);
            m[i][j]=(char)t;
            if(t%10==1) swap(m[i][j],m[(t/10)-1][0]);
        }
       printf("%d\n",bfs());
   }
}

 

时间: 2024-09-14 19:30:24

hdu 1067 Gap的相关文章

hdu 1527

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1527 hint:威佐夫博弈 基本类似于模板 #include <iostream> #include <cmath> #include <cstdio> using namespace std; const double q = (1 + sqrt(5.0)) / 2.0; // 黄金分割数 int Wythoff(int a, int b) { if (a > b)

hdu 2551 竹青遍野

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2551 hint:就是读懂题就行了 #include <iostream> #include <cstdio> using namespace std; typedef long long LL; LL data[1005]; int main() { data[0]=0; for(int i=1; i<1005; i++) data[i]+=data[i-1]+i*i*i; LL

hdu 2054 A == B?

http://acm.hdu.edu.cn/showproblem.php?pid=2054 此题巨坑,刚开始我以为是简单的水题,就用strcmp过, but错了,后来经过我苦思冥想,结果还有几组数据 0.0 和 0,1.000和1.0 , 但是我不太确定前面的0是不是有作用我还是写了,但是有人过的时候,前面的0没考虑比如: 002和2可能是相等的,也可能是不想等的所以不用判断,只能说明hdu数据不是很强啊,嘿嘿 代码如下: #include <iostream> #include <c

hdu 4430 Yukari&#039;s Birthday

点击打开链接hdu 4430 思路:枚举r+二分k 分析: 1 题目要求的是找到一组最小的r*k,如果r*k相同那么就找r最小的. 2 很明显k>=2,根据n <= 10^12,那么可以知道r的最大值r<50,所以只要枚举枚举r的值,然后二分k的大小找到所有的解,存入一个结构体里面,然后在对结构体排序,那么这样就可以得到最后的ans 3 注意题目说了中心点最多一个蜡烛,所以写二分的时候应该注意判断的条件: 4 还有可能计算得到结果超了long long直接变成负数所以应该对或则个进行判断

hdu 1238 Substrings

点击打开链接hdu 1238 思路:kmp+暴力枚举子串 分析: 1 题目要求找到一个子串x,满足x或x的逆串是输入的n个字符串的子串,求最大的x,输出x的长度 2 题目的n最大100,每一个字符串的最大长度为100,那么暴力枚举子串就是o(n^2)才10000肯定是不会超时的,但是由于这里涉及到了逆串的问题,所以我们应该还要求出n个子串的逆串,然后在求最大的x. 代码: #include<iostream> #include<algorithm> #include<cstd

hdu 1857 Word Puzzle

点击打开链接hdu 1857 思路:字典树 分析: 1 题目要求的是给定的单词第一个字母在这个矩形里面的最小的坐标 2 矩形的最大500*500,单词的来源有三个方向,并且单词的起点和终点在矩形之内都是可能的.所以的如果利用枚举矩形之内的单词,那么肯定是超内存的 3 所以我们必须考虑另一种的方法就是对单词进行建字典树,那么我们只要去枚举单词的可能的起点,然后进行查找相应的单词是不是在树上,如果是的话就标记一下当前的坐标. 4 注意由于单词的来源有三个方向,但是因为要求的如果下相同的情况下要求坐标

hdu 1595 find the longest of the shortest

点击打开链接hdu 1595 思路:最短路+优先队列+Dijstra+枚举边 分析: 1 题目要求的是删掉一条边之和求出的最短路中的最大值. 2 很明显,肯定是要先求出原图的最短路并且记录父亲节点.现在我们可以想,如果要枚举所有的边,显然这个是不可能的实现的.所以我们仔细分析可以知道其实能够对最短路产生影响的就是原图最短路上的边,所以我们只需要去枚举删除最短路径上面边然后求最短路即可,最后得到ans 3 这一题的n <= 1000 , m<=n*(n-1)/2 , 刚开始我用的SPFA,然后就

hdu 5280 Senior&amp;#39;s Array

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5280 问题描述 某天学姐姐得到了一个数组A ,在这个数组的所有非空区间中,她找出了一个区间和最大的,并把这个区间和定义为这个数组的美丽值. 但是她觉得这个数组不够美,于是决定修理一下这个数组. 学姐姐将会进行一次操作,把原数组中的某个数修改为P (必须修改). 最后她想使得修改后的数组尽可能美丽.请你帮助她计算经过修理后,这个数组的美丽值最大能是多少? #include <iostream> #i

算法:HDU 4681 String (dp, LCS | 多校8)

题意 给出3个字符串A,B,C,要你找一个字符串D, 要满足下面规定 a) D是A的子序列 b) D是B 的子序列 c) C是D的子串 求D的最大长度 要注意子序列和子串的区别,子序列是不连续的,字串是连 续的 思路 由题目可知,C一定是A和B的子序列,那么先假设C在A和B中只有一个子序列,看下 面例子: abcdefdeg acebdfgh cf 可以看到"cf"在A串的[3, 6]区间 内, 在B串的[2,6]区间(黄色背景) 因为所求的C是D的子串,所以在该黄色区间内的其他字母一