关于两道搜索的题目

Posted 李白莘莘学子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于两道搜索的题目相关的知识,希望对你有一定的参考价值。

T1:

P2383 狗哥玩木棒

题目背景

狗哥又趁着语文课干些无聊的事了...

题目描述

现给出一些木棒长度,那么狗哥能否用给出的木棒(木棒全用完)组成一个正方形呢?

输入格式

输入文件中的第一行是一个整数n表示测试的组数,接下来n行表示每组的测试数据。 每行的第一个数为m(4<=m<=20),接下来m个数ai(1<=ai<=1000)表示木棒的长度。

输出格式

对于每组测试数据,如果可以组成正方形输出“yes”,否则输出“no”。

输入输出样例

输入 #1
3
4 1 1 1 1 
5 10 20 30 40 50 
8 1 7 2 6 4 4 3 5
输出 #1
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表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例

输入 #1
283104765
输出 #1
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;
}
搜索是一项重要偏分技能,希望大家熟练掌握。
完结。


 

以上是关于关于两道搜索的题目的主要内容,如果未能解决你的问题,请参考以下文章

两道关于逆序对的题目

两道关于JS的小考题(闭包与中间件)

LeetCode第3天 - 704. 二分查找 | 35. 搜索插入位置

从两道题看go channel的用法

“金三银四”春招指南!分享两道阿里P7究极难度算法题

2.4继续说说昨天的题---关于递归的几道题目