关于两道搜索的题目
Posted 李白莘莘学子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于两道搜索的题目相关的知识,希望对你有一定的参考价值。
T1:
P2383 狗哥玩木棒
题目背景
狗哥又趁着语文课干些无聊的事了...
题目描述
现给出一些木棒长度,那么狗哥能否用给出的木棒(木棒全用完)组成一个正方形呢?
输入格式
输入文件中的第一行是一个整数n表示测试的组数,接下来n行表示每组的测试数据。 每行的第一个数为m(4<=m<=20),接下来m个数ai(1<=ai<=1000)表示木棒的长度。
输出格式
对于每组测试数据,如果可以组成正方形输出“yes”,否则输出“no”。
输入输出样例
3 4 1 1 1 1 5 10 20 30 40 50 8 1 7 2 6 4 4 3 5
yes no yes
说明/提示
狗哥快抓狂了。
于是我们要帮助一下抓狂的狗哥。
对于正方形,其满足的性质为:4边,等长。
也就是说我们要用木棍组成4边边长为整数的长度完全一样的边。
先做个判断:木棒总长如果不是4的倍数,直接退出。
然后我们可以考虑一个策略:
对于一定的木棒,正方形周长是一定的,为木棒长度总和,于是我们可以进而求出每条边的长度(总长除以4)
我们可以设置4个“桶”,并且在搜索中尝试着“填入”木棒。“桶”内容量只能少于规定容量(边长)如果4个桶正好被填满,也就意味着所有木棒都使用上了,我们就可以直接弹出,找到了一种情况,输出YES。
整个题思路就是这样。
code:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; int read() { int ans=0; char ch=getchar(),last=‘ ‘; while(ch<‘0‘||ch>‘9‘)last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)ans=(ans<<3)+(ans<<1)+ch-‘0‘,ch=getchar(); return last==‘-‘?-ans:ans; } int n,a[21],l[4],m,sum,judge; void dfs(int num) { if(judge)return; if(num>m) { judge=1; return; } for(int i=0;i<4;i++) { if(l[i]>=a[num]) { l[i]-=a[num]; dfs(num+1); l[i]+=a[num]; } } } int main(){ n=read(); for(int j=1;j<=n;j++) { judge=0,sum=0; memset(a,0,sizeof(a)); memset(l,0,sizeof(l)); m=read(); for(int i=1;i<=m;i++) { a[i]=read();sum+=a[i]; } if(sum%4!=0) { printf("no\n"); continue; } for(int i=0;i<4;i++) l[i]=sum/4; dfs(1); if(judge) printf("yes\n"); else printf("no\n"); } return 0; }
T2:
P1379 八数码难题
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入格式
输入初始状态,一行九个数字,空格用0表示
输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
输入输出样例
283104765
4
非常经典的一道题。
对于状态的表示,.每个状态都用3*3的数组表示,但是BFS中需要入队出队,比较麻烦而且空间占用较大,或者是状态压缩,采用一个整数保存状态的数字序列,例如状态1表示为283104765,状态2表示为203184765。
对于判重:判重的实质就是建立状态数字串(一个int数据)和是否出现(一个bool数据)之间的联系,而STL中刚好提供了map<key,value>这样一种容器,我们可以将状态数字串作为key,是否出现作为value直接建立起状态--是否出现的联系。
对于搜索方法的选择,我们可以选择dfs,广度优先搜索,A*搜索方法,三种方法相信大家已经熟练掌握(没错找度娘),在此不再赘述。
code:
#include<cmath> #include<cstdio> #include<iostream> using namespace std; const int d[4]={-1,0,0,1},f[4]={0,-1,1,0},w[9]={2,1,1,1,2,3,3,3,2},z[9]={2,1,2,3,3,3,2,1,1}; int ans=-1,flag,a[4][4]; int read() { int ans=0; char ch=getchar(),last=‘ ‘; while(ch<‘0‘||ch>‘9‘)last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)ans=(ans<<3)+(ans<<1)+ch-‘0‘,ch=getchar(); return last==‘-‘?-ans:ans; } int guess() { int i,j,sum=0; for (i=1;i<4;i++) for (j=1;j<4;j++) if (a[i][j]) sum+=abs(w[a[i][j]]-i)+abs(z[a[i][j]]-j); return sum; } void dfs(int now,int x,int y) { if (flag) return; if (now>ans) return; int v=guess(),i,m,n; if (v+now>ans) return; if (!v) { flag=1; return; } for (i=0;i<4;i++) { m=x+d[i],n=y+f[i]; if (m && m<4 && n && n<4) { swap(a[x][y],a[m][n]); dfs(now+1,m,n); swap(a[x][y],a[m][n]); } } } int main() { int i,j,x,y; for (i=1;i<4;i++) for (j=1;j<4;j++) { a[i][j]=getchar()-48; if (!a[i][j]) x=i,y=j; } while (!flag) ans++,dfs(0,x,y); printf("%d\n",ans); return 0; }
搜索是一项重要偏分技能,希望大家熟练掌握。
完结。
以上是关于关于两道搜索的题目的主要内容,如果未能解决你的问题,请参考以下文章