HDU 1518 木棍凑方阵 DFS经典题 很有代表性的DFS题型 初学者的视角详细注释

题意:给你一堆不同长度的木棍,让你凑成一个正方形,题目短,数据在整型内,因为这题不搞事,专心DFS。

有趣的时光机

思路:1.假如木棍总长度不能达到4的倍数,那你告诉我怎么凑。

2.如果是4的倍数,然后你能凑出三条边,那第四条边是不是默认好了。棒棒哒!

3.DFS搜索题,注意DFS容易超时,这里我用降序排序能在DFS里减少遍历数量,达到剪条小小小枝条的技巧。

感受:很经典的一道DFS题,包含了所有DFS的基本思想和框架。一不小心就wa,一起来玩耍吧。

把cin和cout输入方式改为scanf和printf能再节省一点时间(以前从来没有时间概念,现在觉得时间好重要哦)。或许还有更强的剪枝,但请原谅我的愚蠢,我不会!!大哭大哭大哭



#include <iostream>
#include <algorithm>               //包含sort函数的头文件(算法头文件)
#include <cstring>
using namespace std;

bool visited[22];
int a[22];
int goal,m;

bool cmp(int a,int b)              //sort函数的参数,记得是bool型就好,返回类型就是排序类型
{
    return a>b;
}

bool dfs(int sum,int now,int ans)  //sum是已凑好的边数,now是遍历的下标,ans是离目标边长还需要长度
{
    if(sum==3)                     //能凑够三根的话,那第四根就肯定能凑到啊
        return true;
    for(int i=now;i<=m;i++)        //因为已经是降序的数组了,所以说……比劳资大的数据我还要来干嘛
    {
        if(visited[i])             //判断数据是否已被使用
            continue;
        visited[i]=true;           //标记已用
        if(a[i]==ans)              //哇,满足需求的数目耶,赶紧带走
        {
            if(dfs(sum+1,0,goal))  //凑好了一条边是不是sum++啊,是否从新开始遍历啊(因为now之前的数据有可能有些没被使用的),需求数量是目标边长吧
                return true;       //bool型嘛,如果达到终点就返回真啊
        }
        else if(a[i]<ans)          //大于劳资的请门口左转,顺便把门带上
        {
            if(dfs(sum,i+1,ans-a[i]))  //还没凑好吧,sum不变吧,i前面的肯定比i大啊,要来何用,距离目标减去这个i
                return true;       //道理同上
        }
        visited[i]=false;          //取消使用标记,能走到这的也容易,等于有一条路真的走到黑了,黑到家了(又不是劳资要的答案)
    }
    return false;                  //这个就更惨了,和你的"yes" say goodbye 吧
}

int main()
{
    int n;
    while(cin >> n)
    {
        while(n--)
        {
            cin >> m;
            int sum=0;            //故意在这和dfs都写一个sum变量,让你们更好理解局部变量和全局变量(初学c语时debug好久)
            for(int i=1;i<=m;i++)
            {
                cin >> a[i];
                sum+=a[i];
            }
            if(sum%4)             //不是4地倍数直接say goodbye
            {
                cout << "no" << endl;
                continue;
            }
            sort(a+1,a+m+1,cmp);  //降序排序能减少dfs次数
            goal=sum/4;           //目标边长,外置,因为dfs要用到

            //这里单独用一行说明这条语句的重要性,没有就wa
            //由于acm一般要求多组输入,所以如果不在搞事情之前清零访问数组就会对这一次搞事情产生影响
            //某些数据可能残留上一次的标记,导致一些数据不可用
            memset(visited,false,sizeof(visited));    //包含于字符串头文件

            if(dfs(0,1,goal))     //bool型
                cout << "yes" << endl;
            else
                cout << "no" << endl;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值