1.题目描写叙述:点击打开链接

2.解题思路:本题是一道隐式图的搜索题目。一般来说,这类题目首先要定义状态,接下来是弄清楚状态怎样转移,以及状态怎样判重,怎样推断当前状态是否和目标状态同样。至于求解最短路就是经常使用的BFS就可以。

接下来我们逐一展开讨论。

1.状态的定义:看到这道题,猛一下会想着把每一个字符分别用01表示,然后看成二进制码进行状态压缩,这个状态定义尽管能够,可是显然,状态过于精确和复杂,假设把一行给压缩成一个整数,那么一个完整的图案要用8*9。即72个数才干描写叙述。显然过于庞大。并且对于状态的转移也变得异常复杂。因此这不是一个好的定义。假设我们注意到每一个方块的图案是刚性的这一特定,就会发现。事实上重要的不是图案本身的样子,而是每一个图案相对于初始状态中的图案旋转了多少次。也就是说,我们仅仅须要用0~3就可以准确地描写叙述第i个方块相对于初始状态旋转的次数。这样。我们能够用9个,范围在0~3的整数来描写叙述一个完整的图案。并且,我们发现。这样定义有一个很大的优点就是旋转操作变得很easy,假设是顺时针旋转就是0->1,1->2,2->3,3->0,逆时针反之。因此。这样的定义能够作为一个好的定义。

2.状态的转移:依据题意描写叙述,我们每次都要选择某一块将它顺时针旋转。然后。假设这个方块和相邻的方块之间有齿轮耦合,那么相邻的方块也会被带动旋转。以此类推。

也就是,一个方块的旋转可能会带动多个方块同一时候旋转,看上去挺棘手的。这时我们能够考虑用一下常量数组来处理。由于我们在最初输入的时候还输入了每一个方块上下左右是否具有齿轮。只是要注意,这个“左上右下”是针对初始状态来说的,那么假设我们把第i个方块顺时针旋转90度。此时,新状态的“左上右下”就是原初始状态中的“下左上右”。

再旋转90度。就变成初始状态的“右下左上”,以此类推。

即我们能够设一个状态转移数组来表示这样的情况。用tp[i][j]表示当状态为i(此时的i取值范围是0~3)时,它的第j个下标相应的初始齿轮数组的下标应该是多少(下标从1開始,注意和状态的取值范围分开)。依照刚刚的讨论,tp[0][1]=1,tp[0][2]=2,tp[0][3]=3,tp[0][4]=4。tp[1][1]=4,tp[1][2]=1,tp[1][3]=2,tp[1][4]=3。

设置好了这个常量数组后。我们为了在O(1)时间内获得第i个方块的上下左右相应方块的编号,能够再设置4个常量数组。

分别用up[i],down[i],lef[i],rig[i]来表示。这个数组不难写出。具备了这5个常量数组。rotate函数就很好写了:首先让第i个方块顺时针旋转90度(即相应的值+1就可以),然后用常量数组获得它上下左右的方块编号。用meshed函数推断这4个方块(假设存在的话)是否和第i个方块有齿轮耦合。有的话置1。接下来对于有齿轮耦合的。对它们进行rotate操作。同一时候用vis[i]来标记是否操作过。为了便于表示顺时针和逆时针,我们分别用1。2来表示。比方第i块旋转的编号是flag。那么跟它相邻的就变成3-flag。至于meshed函数,我们能够用上tp数组迅速获得相应的齿轮下标。来确定是否有耦合。

这样,运行完rotate。就完毕了状态转移。

3.状态的判重:我们发现,一共仅仅有9个数。每一个数的变化范围是0~3,因此最好还是写一个Hash函数,将这9个数压缩成一个唯一的整数。

我们发现。0~3占领了2个bit。那么仅仅须要每次把一个数平移2i位就可以。假设下标从1開始。就是2*(i-1)位(第一个数不用移动)。

最多仅仅须要平移16位就可以。

仍然在int范围之内。

并且得到的Hash值一定不会出现反复,能够唯一的表示一个完整的状态。假设我们是通过d数组(BFS中的距离数组)来判重的。那么先初始化为INF。仅仅须要看d[v](v是状态相应的Hash值)是否为INF就可以实现判重。

4.是否到达目标状态:注意,这一步不要和状态判重混淆,由于本题的目标状态实际上能够用多对状态值去描写叙述,而不能够简单的用Hash是否同样来推断。比方题目中的第5块方块。无论它怎样旋转,图案都是一样的。也就是说,第5个状态值是0~3均可能是目标状态的一部分。这就提示我们须要另外找一种推断方法。那么怎样做呢?依据状态的定义。我们能够首先把每一块都尝试旋转4次(不考虑齿轮耦合),看当前旋转的状态是否和目标状态中对应的方块图案全然一样(即这次我们须要用上输入的字符)。

一样的话,就把它标记为1。

假设我们用一个cor数组标记,那么cor[i][j]=1就表示第i个方块顺时针旋转j次后和目标状态的第i块图案一样。这样预处理后,推断函数就不难写了。仅仅须要看对全部的i。是否有cor[i][st[i]]=1就可以(st[i]表示第i个状态值分量)。

至此。我们顺利的攻克了这4大隐式图搜索的问题,剩余的找最短路就是普通的BFS就可以实现,从而完美的攻克了本题。本题对于状态的定义是问题的关键。常量数组的设置也很值得我们学习。

3.代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std; #define me(s) memset(s,0,sizeof(s))
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P; struct State
{
int st[11];
State(){}
State(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9)
{
st[1]=a1,st[2]=a2,st[3]=a3,st[4]=a4,st[5]=a5,st[6]=a6,st[7]=a7,st[8]=a8,st[9]=a9;
}
};
const int INF=100000000;
const int up[]={0,0,0,0,1,2,3,4,5,6};
const int down[]={0,4,5,6,7,8,9,0,0,0};
const int lef[]={0,0,1,2,0,4,5,0,7,8};
const int rig[]={0,2,3,0,5,6,0,8,9,0};
const int tp[4][5]={{0,1,2,3,4},{0,4,1,2,3},{0,3,4,1,2},{0,2,3,4,1}};
queue<State>q;
string s[10][10],t[10][10],p[10];
int st[11][11];
int vis[11];
int cor[11][11];
int d[1<<20];
int ans; void init_initial()
{
for(int i=0;i<3;i++)
for(int j=1;j<=8;j++)
cin>>s[i*3+1][j]>>s[i*3+2][j]>>s[i*3+3][j];
} void init_target()
{
for(int i=0;i<3;i++)
for(int j=1;j<=8;j++)
cin>>t[i*3+1][j]>>t[i*3+2][j]>>t[i*3+3][j];
} int Hash(State x)//对状态x进行压缩
{
int res=0;
for(int i=1;i<=9;i++)
res=res+(x.st[i]<<(2*(i-1)));
return res;
} bool meshed(State x,int a,int e1,int b,int e2)//推断第a个方块的e1方位和第b个方块的e2方位是否都有齿轮
{
int f1=st[a][tp[x.st[a]][e1]],f2=st[b][tp[x.st[b]][e2]]; //利用tp数组高速获得相应下标
return f1==1&&f2==1; //都是1,说明有齿轮耦合
} State rotate(State x,int y,int flag)
{
vis[y]=1;
int l=lef[y],r=rig[y],u=up[y],d=down[y];
bool fl=0,fu=0,fd=0,fr=0;
if(l&&!vis[l]&&meshed(x,l,3,y,1))fl=1;
if(r&&!vis[r]&&meshed(x,r,1,y,3))fr=1;
if(u&&!vis[u]&&meshed(x,u,4,y,2))fu=1;
if(d&&!vis[d]&&meshed(x,d,2,y,4))fd=1;
int z=x.st[y];
if(flag==1) z=(z==3)?0:z+1; //对第y块方块顺时针旋转90度
else z=(z==0)?3:z-1;
x.st[y]=z;
if(fl&&!vis[l])//假设第y块方块的左边发生齿轮耦合,且它没有旋转过,那么对左側的方块进行旋转
{
vis[l]=1;
x=rotate(x,l,3-flag);
}
if(fr&&!vis[r])
{
vis[r]=1;
x=rotate(x,r,3-flag);
}
if(fu&&!vis[u])
{
vis[u]=1;
x=rotate(x,u,3-flag);
}
if(fd&&!vis[d])
{
vis[d]=1;
x=rotate(x,d,3-flag);
}
return x;
} bool ok(State y)//利用cor数组实现对到达目标状态的推断
{
for(int i=1;i<=9;i++)
if(!cor[i][y.st[i]])return 0;
return 1;
} void bfs(State x)
{
while(!q.empty())q.pop();
q.push(x);
while(!q.empty())
{
x=q.front();q.pop();
int sx=Hash(x);
for(int i=1;i<=9;i++)
{
me(vis);
State y=rotate(x,i,1);
int sy=Hash(y);
if(d[sy]>d[sx]+1)
{
d[sy]=d[sx]+1;
if(ok(y))
{
ans=d[sy];
return;
}
q.push(y);
}
}
}
} bool same(int x)
{
for(int i=1;i<=8;i++)
for(int j=0;j<8;j++)
if(s[x][i][j]!=t[x][i][j])return 0;
return 1;
}
void change(int x)  //对第x个方块旋转90度(不考虑齿轮耦合)
{
for(int i=1;i<=8;i++)p[i]="";
for(int i=1;i<=8;i++)
for(int j=8;j>=1;j--)
p[i]=p[i]+s[x][j][i-1];
for(int i=1;i<=8;i++)
s[x][i]=p[i];
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init_initial(); //初始化初始状态
init_target(); //初始化目标状态
for(int i=1;i<=9;i++)
for(int j=1;j<=4;j++)
scanf("%d",&st[i][j]); //齿轮数组
fill(d,d+(1<<20),INF); //把全部的距离都设为INF
d[0]=0,ans=-1;
me(cor);
for(int i=1;i<=9;i++)
for(int j=0;j<4;j++) //对每一个方块的第j次旋转是否等于目标状态进行预处理
{
if(same(i))cor[i][j]=1;
change(i);
}
bfs(State(0,0,0,0,0,0,0,0,0)); //利用BFS求最短路
printf("%d\n",ans);
}
}

ZOJ 3814 Sawtooth Puzzle (2014年牡丹江赛区网络赛F题)的更多相关文章

  1. ZOJ 3810 A Volcanic Island (2014年牡丹江赛区网络赛B题)

    1.题目描写叙述:点击打开链接 2.解题思路:本题是四色定理的模板题.只是有几种情况要提前特判一下:n==1直接输出,1<n<5时候无解,n==6时候套用模板会出现同样的块.因此要特判一下 ...

  2. ZOJ 3811 / 2014 牡丹江赛区网络赛 C. Untrusted Patrol bfs/dfs/并查集

    Untrusted Patrol Time Limit: 3 Seconds                                     Memory Limit: 65536 KB    ...

  3. hdu 4045 2011北京赛区网络赛F 组合数+斯特林数 ***

    插板法基础知识 斯特林数见百科 #include<iostream> #include<cmath> #include<cstdio> #include<cs ...

  4. hdu 4031 2011成都赛区网络赛A题 线段树 ***

    就是不知道时间该怎么处理,想了好久,看了别人的题解发现原来是暴力,暴力也很巧妙啊,想不出来的那种  -_-! #include<cstdio> #include<iostream&g ...

  5. hdu 4036 2011成都赛区网络赛F 模拟 **

    为了确保能到达终点,我们需要满足下面两个条件 1.能够到达所有山顶 2.能够在遇到苦土豆时速度大于他 二者的速度可以用能量守恒定律做,苦土豆的坐标可通过三角形相似性来做 #include<cst ...

  6. hdu 4026 2011上海赛区网络赛F TSP ****

    没看过TSP,先mark //4838039 2011-10-27 23:04:15 Accepted 4026 2343MS 31044K 3143 B C++ Geners //状态压缩DP的TS ...

  7. hdu 4006 优先队列 2011大连赛区网络赛F **

    签到题都要想一会 #include<cstdio> #include<iostream> #include<algorithm> #include<cstri ...

  8. Fantastic Graph 2018 沈阳赛区网络预赛 F题

    题意: 二分图 有k条边,我们去选择其中的几条 每选中一条那么此条边的u 和 v的度数就+1,最后使得所有点的度数都在[l, r]这个区间内 , 这就相当于 边流入1,流出1,最后使流量平衡 解析: ...

  9. Largest Point (2015沈阳赛区网络赛水题)

    Problem Description Given the sequence A with n integers t1,t2,⋯,tn. Given the integral coefficients ...

随机推荐

  1. 316 Remove Duplicate Letters 去除重复字母

    给定一个仅包含小写字母的字符串,去除重复的字母使得所有字母出现且仅出现一次.你必须保证返回结果是所有可能结果中的以字典排序的最短结果.例如:给定 "bcabc"返回 "a ...

  2. Python随笔-快排

    def swap(arr, i, j): temp = arr[i] arr[i] = arr[j] arr[j] = temp def part(arr, beg, end): : return b ...

  3. java DDD 基于maven开发的探讨

    对于DDD我目前的理解是 1.除了数据的基本操作,也可以把一些公用的方法或者类迁移到Infrastructrue 2.对于domain层可以声明各个聚合根的操作接口:例:IXXXRepository ...

  4. 【年终糖果计划】跟风领一波糖果 candy.one 领取教程

    糖果领取网址(较为稳定):https://candy.one/i/1474564 用微信和QQ打开的朋友请复制到其他浏览器打开 糖果领取网址(较为稳定):https://candy.one/i/147 ...

  5. html5——应用缓存

    基本概念 1.HTML5中我们可以轻松的构建一个离线(无网络状态)应用,只需要创建一个cache manifest文件 2.可配置需要缓存的资源,网络无连接应用仍可用,本地读取缓存资源,提升访问速度, ...

  6. [Windows Server 2008] ASP.net安装方法

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装ASP.n ...

  7. 【VHDL】深度讲解二进制无符号和有符号加法处理溢出的问题

    1.Unsigned adders 这个比较简单,只需在A.B前面扩展一位0防止溢出,溢出的数填到第n位cout,n-1到0位就是sum. , 2.Signed adders 一开始也搞不懂下图中为什 ...

  8. Centos6.7 编译安装 Apache PHP

    Centos6.7 编译安装 Apache PHP 原文地址:http://www.cnblogs.com/caoguo/p/4968039.html ##### Apache 编译安装 #### [ ...

  9. codeforces_731D_(前缀和)(树状数组)

    D. 80-th Level Archeology time limit per test 2 seconds memory limit per test 256 megabytes input st ...

  10. day08-字符编码

    目录 计算机基础 启动应用程序 写文本的流程 Python解释器执行文件的原理 Python解释器与文本编辑器的区别 字符编码 字符编码发生在哪三个阶段 字符编码发展史与分类 总结 Python2与P ...