刷题交流|揭露抖音骗局 - 斗地主残局问题
3688
2023.03.01
2023.03.02
发布于 未知归属地

IMG_3960.jpg
下面先走
抖音上看到的,我想了一晚上, 搞不定,想来leetcode看看大神有没有解法.
另外,如果用程序做通用解的话该怎么算, 代码量还是挺大的, 如果有的说下大概思路就可以.

---------------------------最终结果----------------------------
想睡觉的,但是心理不爽, 于是代码写出来了, 输入两个数组a和b. a先发牌, 运行结果会告诉你下一步发那张牌, 如果是死局,会提示没有答案.
出牌后手动更新下两个数组,把上一回合对手出的牌填在startPush数组中, 然后再计算下一步.
下面是代码, 有些很特殊的发牌还不支持(比如多个炸弹等等),而且运行速度比较慢,有些多余的代码没有删掉, 还没有来得及优化
上面这个残局我自己运行了大概十几分钟吧.

结果是这就是个死局

献上代码:

//
//  main.cpp
//  doudizhu
//
//  Created by alex on 2023/3/2.
//

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
using namespace std;

//暂时没有考虑大小王炸弹,多个炸弹也没有考虑, 连对没有考虑, 多个三带几也没有考虑
#define King_Small 16
#define King_Big 17

map<int,int> vector2map(vector<int> v)
{
    map<int,int> s;
    for(int i = 0;i < v.size(); ++ i)
    {
        if(s.contains(v[i]))
            s[v[i]] ++ ;
        else
            s[v[i]] = 1;
    }
    return s;
}

//长度为2的map是否符合
bool isMapLengthEquad(map<int,int>m, int length1, int length2)
{
    if(m.size() != 2)
        return false;
    int a =  (*(m.begin())).second;
    auto it = m.begin();
    ++it;
    int b =(*(it)).second;
    if(a == length1 && b == length2)
        return true;
    if(a == length2 && b == length1)
        return true;
    
    return  false;
}


bool isVectorEqual(vector<int> v1, vector<int> v2)
{
    if(v1.size() != v2.size())
        return  false;
    for(int i = 0;i < v1.size(); ++ i)
    {
        if(v1[i] != v2[i])
            return  false;
    }
    
    
    return true;
}
//长度为3的map是否符合
bool isMapLengthEquad(map<int,int>m, int length1, int length2, int length3)
{
    if(m.size() != 2)
        return false;
    int a =  (*(m.begin())).second;
    auto it = m.begin();
    ++it;
    int b =(*(it)).second;
    ++it;
    int c = (*(it)).second;
    vector<int> v1;
    v1.push_back(a);
    v1.push_back(b);
    v1.push_back(c);
    vector<int> v2;
    v2.push_back(length1);
    v2.push_back(length2);
    v2.push_back(length3);
    sort(v1.begin(), v1.end());
    sort(v2.begin(), v2.end());
    if(isVectorEqual(v1,v2))
        return  true;
    
    return  false;
}


bool isBomb(map<int,int> m)
{
    if(m.size() == 1)
        return m.begin()->second == 4;
    else if(m.size() == 3)
        return isMapLengthEquad(m, 4, 1, 1) || isMapLengthEquad(m, 4, 2, 2);
    return  false;
}

//v有顺序
bool isSequence(vector<int> v)
{
    for(int i = 0;i < v.size(); ++ i)
    {
        if(v[i] >= 15)
            return false;
    }
    for(int i = 1;i < v.size(); ++ i)
    {
        if(v[i] - v[i-1] != 1)
            return  false;
    }
    
    return  true;
}

bool isOK(vector<int> v)
{
    sort(v.begin(), v.end());
    if(v.size() == 0)
        return true;
    else if(v.size() == 1)
        return true;
    else if(v.size() == 2)
    {
        return v[0] == v[1];
    }
    else if(v.size() == 3)
    {
        return v[0] == v[1] && v[1]== v[2];
    }
    else if(v.size() == 4)
    {
        //炸弹
        if(v[0] == v[1] && v[1]== v[2] && v[2] == v[3])
            return true;
        //是否是3带1
        if(isMapLengthEquad(vector2map(v), 3, 1))
            return true;
        return false;
    }
    else if(v.size() == 5)
    {
        //是否是3带1对
        set<int> s;
        if(isMapLengthEquad(vector2map(v), 3, 2))
            return true;
        if(isSequence(v))
            return true;
        return false;
    }
    else if(v.size() == 6)
    {
        //是否是4带2
        auto m = vector2map(v);
        if(isMapLengthEquad(m,4,1,1))
            return true;
    }
    else if(v.size() == 8)
    {
        //是否是4带2对
        auto m = vector2map(v);
        if(isMapLengthEquad(m,4,2,2))
            return true;
    }
        
    return isSequence(v);
}


int pow2(int t)
{
    int ret = 1;
    while(t --)
    {
        ret *= 2;
    }
    return  ret;
}


void printVector(const vector<int>& v)
{
    for(int i = 0;i < v.size(); ++ i)
    {
        printf("%d,", v[i]);
    }
    printf("\n");
}

vector<int> mapsize2vector(map<int,int> m)
{
    vector<int> ret;
    for(auto it = m.begin(); it != m.end(); ++ it)
    {
        ret.push_back(it->second);
    }
    return ret;
}

bool isSameMap(map<int,int>& m1, map<int, int>& m2)
{
    auto v1 = mapsize2vector(m1);
    auto v2 = mapsize2vector(m2);
    sort(v1.begin(), v1.end());
    sort(v2.begin(), v2.end());
    return v1 == v2;
}

int getMainEleInMap(map<int,int>&m)
{
    int ret = 0;
    int max = 0;
    for(auto it = m.begin(); it != m.end(); ++ it)
    {
        int num = it->second;
        if(num >= max)
        {
            max = num;
            ret = it->first;
        }
    }
    
    
    return ret;
}

bool canPushForSequence(const vector<int>& now, const vector<int>& last)
{
    //先前为空,现在必须出
    if(last.size() == 0)
        return now.size() > 0;
    //先前不为空,必须是炸弹或者同类型的,或者为空
    if(now.size() == 0)
        return true;
    auto map_now = vector2map(now);
    auto map_last = vector2map(last);
    if(isBomb(map_now))
    {
        //判断炸弹是否大过之前的
        if(map_now.begin()->first  > map_last.begin()->first)
            return  true;
        return false;
    }
    //不是同一类型
    bool isSame = isSameMap(map_now, map_last);
    if(!isSame)
        return false;
    
    //是同一类型
    //是顺子
    if(isSequence(now))
    {
        return now[now.size()-1] > last[last.size()-1];
    }
    //不是顺子
    return getMainEleInMap(map_now) > getMainEleInMap(map_last);
    
    return  true;
}

vector<vector<int>> getAllPushMethod(const vector<int>& a)
{
    int all = pow2(a.size());
    vector<vector<int>> ret;
    set<vector<int>> vis;
    for(int i = 0;i < all; ++ i)
    {
        vector<int> one;
        for(int k = 0;k < a.size(); ++ k)
        {
            if(i & (1<<k))
            {
                one.push_back(a[k]);
            }
        }
        if(vis.contains(one))
            continue;
        if(isOK(one))
        {
            ret.push_back(one);
            //printVector(one);
        }
        vis.insert(one);
    }
    
    //vector<int> one;
    //ret.push_back(one);
    return ret;
}

vector<int> vectorMinus(const vector<int>& a, const vector<int>& b)
{
    vector<int> ret = a;
    for(int i = 0;i < b.size(); ++ i)
    {
        auto it = find(ret.begin(), ret.end(), b[i]);
        ret.erase(it);
    }
    
    return ret;
}

bool canSolove(const vector<int>&a,const vector<int>& b,const vector<int>& last_push,int step,vector<vector<int>> _solution)
{
    
    
    auto va = getAllPushMethod(a);
    auto vb = getAllPushMethod(b);
    for(int i = 0;i < va.size(); ++ i)
    {
        if(step == 0)
        {
            printf("step(%d) : %d/%d\n",step,i,va.size());
        }
        else if(step == 1)
        {
            printf("\tstep(%d) : %d/%d\n",step,i,va.size());
        }
        else if(step == 2)
        {
            printf("\t\tstep(%d) : %d/%d\n",step,i,va.size());
        }
        else if(step == 3)
        {
            printf("\t\t\tstep(%d) : %d/%d\n",step,i,va.size());
        }
        else if(step == 4)
        {
            printf("\t\t\t\tstep(%d) : %d/%d\n",step,i,va.size());
        }
        
        vector<int> push_a = va[i];
        
        if(canPushForSequence(push_a, last_push)==false)
        {
            continue;
        }
        //printf("push_a: ");
        //printVector(push_a);
        vector<int> left_a = vectorMinus(a, push_a);
        
        vector<vector<int>> solution = _solution;
        solution.push_back(push_a);
        if(left_a.size() == 0)
        {
            /*if(step == 0)
            {
                printf("得到一个解决方案\n");
                for(int i = 0;i < solution.size(); ++ i)
                {
                    printf("\t");
                    printVector(solution[i]);
                }
            }*/
            //solution.erase(solution.begin() + 1);
            return true;
        }
        bool allOk = true;
        for(int j = 0;j < vb.size(); ++ j)
        {
            vector<int> push_b = vb[j];
            vector<int> left_b =vectorMinus(b, push_b);
            
            
            if(canPushForSequence(push_b, push_a)== false)//不能出
            {
                continue;
            }
                
            //printf("push_b: ");
            //printVector(push_b);
            //失败了
            if(left_b.size() == 0)
            {
                allOk = false;
                break;
            }
                
            
            //能出,深度搜索
            auto childHasSolution = canSolove(left_a, left_b, push_b, step + 1,solution);
            if(!childHasSolution) //存在子牌没有解决方案
            {
                allOk = false;
                break;
            }
        }
        //solution.erase(solution.begin() + 1);
        if(allOk)
        {
            if(step == 0)
            {
                printf("下一步应该出");
                printVector(push_a);
            }
            
            
            return true;
        }
    }
    
    return false;
}


int main(int argc, const char * argv[]) {
    vector<int> a = {King_Big,7,6,5,4,3,3,3,3};
    vector<int> b = {King_Small,8,8,8,8,7,6,5,4};
    //vector<int> a = {1, 3,4,5,6,7};
    //vector<int> b = {4,4,5,5};
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    //vector<int> a = {5,4,3,3};
    
//    printf("------a---------\n");
//    auto va = getAllPushMethod(a);
//    printf("------b---------\n");
//    auto vb = getAllPushMethod(b);
    
    vector<int> startPush;
    vector<vector<int>> solution;
    auto s = canSolove(a,b,startPush, 0, solution);
    printf(" ---输出结果----");
    if(s)
    {
        printf("有解决方案\n");
    }
    else
    {
        printf("没有解决方案\n");
    }
    
    return 0;
}
评论 (31)