集合划分问题-DFS与回溯

集合划分问题

集合划分问题是对这样一类问题的抽象,即原始问题包含一些列可能结果,不断的划分出子集并研究剩余的集合能否继续划分,即问题能否最终求解,通常采取dfs进行求解

题目描述
一种卡牌游戏,规则如下:

总共有36张牌,每张牌是1~9。每个数字4张牌。
你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
14张牌中有2张相同数字的牌,称为雀头。
除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)

例如:

1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌
1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌
1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。

现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。

输入描述:
输入只有一行,包含13个数字,用空格分隔,每个数字在1~9之间,数据保证同种数字最多出现4次。
输出描述:
输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0

示例1
输入
1 1 1 2 2 2 5 5 5 6 6 6 9
输出
9
说明
可以组成1,2,6,7的4个刻子和9的雀头

求解思路

容易知道最终的问题为:判定14张牌能否构成和牌
首先讨论哪些牌可以作为雀头(必须数量大于等于2)
然后剩下的牌能否进行这样的划分:
①对于一个数字x,其划分为重复子集合,即{x、x、x}
②对于一个数字x,其划分为连续子集合,即{x、x+1、x+2}
若能进行划分,那么剩下的牌继续执行划分逻辑,直到所有的牌划分干净

实现细节

采取map<int,int>记录每种牌的数量,采取map.count 等函数研究某种牌是否存在以及剩余数量
采取传引用方式进行dfs操作,易错点:进入下一层递归,map对应节点-=i 递归返回后 对应节点+=i

代码实现

#include<iostream>
#include<vector>
#include<map>
using namespace std;
bool dfs(map<int,int>& mp)  //研究这些数字能否被划空
{
    int count=0;
    for(auto item:mp)
        count+=item.second;
    if(count==0)
        return true;//已经划空了

    for(auto item:mp)
    {
        //研究item划成重复成员
        if(item.second>=3)
        {
            mp[item.first]-=3;
            if(dfs(mp))
                return true;
            mp[item.first]+=3;
        }
        if(item.second>0 && mp.count(item.first+1)>0 && mp.count(item.first+2)>0 && mp[item.first+1]>0 && mp[item.first+2]>0)  //研究划分为顺子(以item为起点)
        {
            mp[item.first]-=1;
            mp[item.first+1]-=1;
            mp[item.first+2]-=1;
            if(dfs(mp))
                return true;
            mp[item.first]+=1;
            mp[item.first+1]+=1;
            mp[item.first+2]+=1;
            
        }

    }
    //所有的item研究过了
    return false;

}
bool func(vector<int>& arr )
{
    //判断arr中是否可以和牌子
    map<int,int> mp;
    for(auto item:arr)
    {
        mp[item]++;  //计数
    }
    //研究可能的雀头
    for(auto item:mp)
    {
        if(item.second>=2)  //首先必须大于2
        {
            map<int,int> mp2=mp;
            mp2[item.first]-=2;//减去这两个
            if(dfs(mp2))
                return true;
            
            
        }
    }
    return false;

}
int main()
{
    
    
    vector<int> a;
    vector<int> arr(10,4);
    for(int i=0;i<13;i++)
    {
        int temp;
        cin>>temp;
        a.push_back(temp);
        arr[temp]--;//对应的牌的数量减少
    }
    bool flag=false;
    //研究剩余的牌中加入某个数字 是否可以和牌
    for(int i=1;i<10;i++)
    {
        if(arr[i]>0) //首先必须有剩余
        {
            vector<int> par=a;
            par.push_back(i);
            if(func(par))
            {
                cout<<i<<" ";
                flag=true;
            }
             
        }
    }
    if(flag==false)
        cout<<0<<endl;
 
}
已标记关键词 清除标记
相关推荐
<p> <b><span style="font-size:14px;"></span><span style="font-size:14px;background-color:#FFE500;">【Java面试宝典】</span></b><br /> <span style="font-size:14px;">1、68讲视频课,500道大厂Java常见面试题+100个Java面试技巧与答题公式+10万字核心知识解析+授课老师1对1面试指导+无限次回放</span><br /> <span style="font-size:14px;">2、这门课程基于胡书敏老师8年Java面试经验,调研近百家互联网公司及面试官的问题打造而成,从筛选简历和面试官角度,给出能帮助候选人能面试成功的面试技巧。</span><br /> <span style="font-size:14px;">3、通过学习这门课程,你能系统掌握Java核心、数据库、Java框架、分布式组件、Java简历准备、面试实战技巧等面试必考知识点。</span><br /> <span style="font-size:14px;">4、知识点+项目经验案例,每一个都能做为面试的作品展现。</span><br /> <span style="font-size:14px;">5、本课程已经在线下的培训课程中经过实际检验,老师每次培训结束后,都能帮助同学们运用面试技巧,成功找到更好的工作。</span><br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><b>【超人气讲师】</b></span><br /> <span style="font-size:14px;">胡书敏 | 10年大厂工作经验,8年Java面试官经验,5年线下Java职业培训经验,5年架构师经验</span><br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><b>【报名须知】</b></span><br /> <span style="font-size:14px;">上课模式是什么?</span><br /> <span style="font-size:14px;">课程采取录播模式,课程永久有效,可无限次观看</span><br /> <span style="font-size:14px;">课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化</span><br /> <br /> <br /> <span style="font-size:14px;background-color:#FFE500;"><strong>如何开始学习?</strong></span><br /> <span style="font-size:14px;">PC端:报名成功后可以直接进入课程学习</span><br /> <span style="font-size:14px;">移动端:<span style="font-family:Helvetica;font-size:14px;background-color:#FFFFFF;">CSDN 学院APP(注意不是CSDN APP哦)</span></span> </p>
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页