两道DFS水题

距离noip2018提高组的比赛还有三个月,然而今天却卡在这两个普及-的题上。。。。。。(其实就是我 太菜了)

这里写图片描述

这里写图片描述

先看第一题 洛谷P1433吃奶酪

题目描述: 房间里放着n块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处。

输入格式: 第一行一个数n (n<=15)

接下来每行2个实数,表示第i块奶酪的坐标。

两点之间的距离公式: sqrt((x1-x2)(x1-x2)+(y1-y2)(y1-y2))

输出格式:

一个数,表示要跑的最少距离,保留2位小数。

输入样例#1:

4

1 1

1 -1

-1 1

-1 -1

输出样例#1:

7.41

这是一道比较裸的dfs题了,首先,为了方便在搜索中便于计算,可以先把任意两点间的距离存储下来;

定义一个数组jul,jul [ i ][ j ] 表示第i块奶酪到第j块奶酪之间的距离,在输入的时候就顺便操作了,但是要注意,别忘了把(0,0)和其他点的距离存上,因为小老鼠是从(0,0)开始的;

然后就是dfs了,但是如果不剪枝的话复杂度在15!左右,会tle,所以要剪枝;

只需要一个非常简单的剪枝就可以啦,用now来记录当前走过的距离,ans记录已经找到的最短距离,当now>ans的时候直接return,能节省不少时间;

这里写图片描述

上代码QwQ

#include<bits/stdc++.h>              //懒人(菜鸡)必备万能头文件
using namespace std;
struct mp{
    double x,y;
}a[16];                              //用a数组来记录每个点的坐标(本菜鸡喜欢用结构体)
int n,t;
double jul[16][16],now,ans=9999999;
bool b[16];
void dfs(int x)
{
    if(now>ans)return;                //剪枝
    if(t==n){
        ans=min(now,ans);
        return;
    }
    for(int i=1;i<=n;i++)
    if(!b[i])
    {
        b[i]=true;
        now+=jul[x][i];
        t++;
        dfs(i);
        b[i]=false;                   //回溯
        now-=jul[x][i];
        t--;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%lf%lf",&a[i].x,&a[i].y);
    a[0].x=0;a[0].y=0;                //好像没用的初始化
    for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++)
    {
        double x1=a[i].x,x2=a[j].x,y1=a[i].y,y2=a[j].y;
        jul[i][j]=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        jul[j][i]=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        //记录i和j之间的距离
    }
    dfs(0);
    printf("%.2f",ans);
    return 0;
}

本题完美结束~

第二题:

先描述一下我看到这个普及-的题后的心情

这里写图片描述

这只是普及-的题啊,这难度的题做不出来还比个啥?

这里写图片描述

一中的男人绝不能轻易认输。。。。。。

然而————在尝试着写了代码以后,我还是不得不认输了。。。

呜呜呜……嘤嘤嘤……我好菜啊……

这里写图片描述

于是,诚实(虚伪)的我默默地点开了题解……

这里写图片描述

借鉴了一下大佬的思路,但是

代码是我自己写的!!!

代码是我自己写的!!!

代码是我自己写的!!!

好了,在扯了一阵子以后,开始讲题;

题目描述

一个N×M 的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻 88 个格子中的一个即认为这两个数字相邻),求取出数字和最大是多少。

输入输出格式

输入格式: 第1行有一个正整数 T ,表示了有 T 组数据。

对于每一组数据,第一行有两个正整数 N 和 M ,表示了数字矩阵为 N 行 M 列。

接下来 N 行,每行 M 个非负整数,描述了这个数字矩阵。

输出格式: T 行,每行一个非负整数,输出所求得的答案。

思路:从上往下,从左往右,一个一个地搜;

用bool b[7][7]数组来记录(i,j)点是否被取过;判断一个点是否可以取,就看看它附近已经搜到过的点是否被取过,如果附近有被取过的点就继续往后搜,如果没有就取这个点的数,再继续搜;

这个代码中,坐标轴是这样的:

这里写图片描述

上代码

#include<bits/stdc++.h>
using namespace std;
int l,t,a[7][7],n,m,now=0,ans[25],sum=0,tt;
bool b[7][7],pd;
void dfs(int x,int y,int z)
{
    if(x>n){
        sum=max(z,sum);
        return;
    }
    int xl=x,yl=y+1;
    if(yl>m){
        xl++;yl=1;
    }
    if(!b[x-1][y]&&!b[x][y-1]&&!b[x-1][y-1]&&!b[x-1][y+1])
    {
    //如果他上面的所有已搜的点没有被取的,就取这个点
        b[x][y]=1;
        dfs(xl,yl,z+a[x][y]);//继续搜(更新z的值)
        b[x][y]=0;
    }
    dfs(xl,yl,z);//否则跳过(即不更新z的值),继续搜
}
int main()
{
    scanf("%d",&l);
    while(l--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
        dfs(1,0,0);
        printf("%d\n",sum);
        sum=0;
    }
    return 0;
}
/*
1
2 2
3 4
1 1
*/

最后感谢红名题解大佬 Harry_Potter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值