关于两道搜索的题目

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


原文地址:https://www.cnblogs.com/lbssxz/p/12678683.html

时间: 2024-09-30 00:01:55

关于两道搜索的题目的相关文章

两道有意思的题目

碰到两道有意思的题目,记录一下. 题目一: 问,对于任意一个正整数,是否存在一个它的倍数全是由1和0组成? 例如: 1 * 1 = 1 2 * 5 = 10  (2的5倍是10,10由1和0组成) 3 * 37 = 111 (3 的 37 倍是111,111 全部由1组成) 4 * 25 = 100 (4 的 25 倍是100,100 由1和0组成) 5 * 20 = 100 (5 的 20 倍是100,100由1 和 0 组成) …… 现在需要判断,随便给一个正整数,是否存在一个它的倍数满足题

分享两道笔试题目

前几天,给成都的某家公司投了个简历,给发了两道笔试题目,与大家分享一下.附上自己的解题过程,写得不好的地方,还请博友多多指教. 一 .  设计程序输出销售及收费清单 一个电商平台对在其平台之上销售的除了书籍.食品以及药物以外的商品收取 10% 的费用.而对于进口的商品则额外收取 5% 的附加费用.对于平台抽取的费用计算时,舍入的规则是:对于 n% 抽取率,价格为 p的商品, np/100 的值就近舍入到 0.05(如: 7.125 -> 7.15, 6.66 -> 6.70 ). 卖家卖出一些

简单小程序——产生三十道小学四则运算题目

题目要求程序可以生成三十道小学四则运算题目. 因为要随机生成题目,则需要产生随机数,因此我上网搜索了生成随机数的方法,选择了使用Random类得到规定范围内的随机数.因为一个运算需要三个元素,两个参与运算的数字,一个运算符(加减乘除),因此需要获得三个随机数,其中一个随机数的范围为1~4,对应加减乘除四个运算符.在程序中需要特别注意的是除法的运算题目生成,由于是小学题目,因此要生成可以整除的运算式.因此在除法的运算阶段,我进行了判断,若当前产生的两个随机数不能实现整除或者除数为零,便重新获得两个

ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)

两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路. POJ3268-Silver Cow Party //计算正逆最短路径之和的最大值 //Time:32Ms Memory:360K #include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<algorithm> using namespace std; #define

告诉我图样图森破的两道简单C++笔试题

今晚刷了一大堆的笔试题,中规中矩,但是有两道做得很快但是都错了的题目,印象深刻. (要找工作的大四渣有没有共鸣,在学校明明很努力,但是总是跟不上时代,没有厉害的项目,也没有过人的竞赛成绩,内推屡屡失败,前天阿里巴巴在线笔试也被虐死,真心迷惘,唯独刷题搞笔试了.) 第一道题是关于宏定义的. #include<iostream> using namespace std; #define fun(n) (n-1)*n int main() { int x=3; cout<<fun(x+3

ACM 暴力搜索题 题目整理

UVa 129 Krypton Factor 注意输出格式,比较坑爹. 每次要进行处理去掉容易的串,统计困难串的个数. #include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include

水了两道括号匹配

POJ 1141 给一段括号序列,要求增加最少的括号,使之合法,输出序列. dp[i][j]表示使给定序列的i到j成为合法序列所需添加的最少括号数,dp[0][length-1]即是答案,转移的话,如果s[i]和s[j]可以匹配那么dp[i][j] = dp[i+1][j-1],否则就考虑在中间选择一个位置m,使分割成的两个序列各自成为合法序列.方案的话就是多开一个数组记录然后递归输出.状态是从长度小的序列转移到长度长的序列,所以两层循环,外层枚举长度,内层枚举头位置即可.写成记忆化搜索简单一点

两道拓扑排序的问题

多久没写东西了啊.... 两道拓扑排序Liv.1的题....方法是一样的~~ <拓扑排序·二> 题目:http://hihocoder.com/contest/hiho81/problem/1 一个电脑网路,单向边,如果存在边u->v,那么u的病毒会感染到v. 要点,不存在环!那么如果u的入度=0的话,那么u中的病毒数不会再变化. 想到拓扑排序.不断删去入度为0的点.每次删去节点u,如果存在u->v,那么病毒数 num[v] += num[u].问题解决. (用queue实现拓扑排

病毒的侵扰和再侵扰两道AC自动机的应用

HDU2896 病毒的侵扰 http://vjudge.net/problem/viewProblem.action?id=16404 题目大意: 记录每个病毒的编号,并给出一些网站的源码,分别输出网站及其对应编号中所含病毒的编号,没有就不输出 最后输出有病毒网站的个数 这道题需要注意的是这个所有ASCII码均会用到,所以我之前傻傻地写str[i]-'a'还不知为什么会错简直苦逼~~ 这里直接用ch[now][str[i]]找到对应位置即可 因为要记录编号,为了防止重复访问,我对query中进行