题目来源
阿里巴巴2020实习生招聘在线笔试(3月20日场)
题目描述
有一叠扑克牌,每张牌介于1和10之间,有四种出牌方法:
单牌
对子
顺子:如12345
连对:如112233
给10个数,表示1-10每种牌有几张,问最少要多少次能出完
输入样例
1 1 1 2 2 2 2 2 1 1
输出样例
3
样例说明:出三个顺子:12345,45678,678910
思路:枚举+回溯剪枝
下面的代码中增加了输出最佳结果的操作。
#include <iostream>
#include <vector>
using namespace std;
void dfs(vector<int> &cards, int times, int &least, vector<vector<int>> &path, vector<vector<int>> &res){
if(times > least) return; // 剪枝
int first=0;
for(; first<cards.size(); first++)
if(cards[first])
break;
if(first== cards.size()){ // 到达叶子结点
if(times<least) {
least = times;
res = path;
}
return;
}
// 出单牌
cards[first]--;
path.push_back(vector<int> {first});
dfs(cards, times+1, least, path, res);
path.pop_back();
cards[first]++;
// 出对子
if(cards[first]>=2){
cards[first]-=2;
path.push_back(vector<int> {first, first});
dfs(cards, times+1, least, path, res);
path.pop_back();
cards[first] +=2;
}
// 出顺子
if(first+4<cards.size()){
if(cards[first]&&cards[first+1]&&cards[first+2]&&cards[first+3]&&cards[first+4]){
for(int i=first; i<=first+4; i++)
cards[i]--;
path.push_back(vector<int> {first, first+1,first+2, first+3,first+4});
dfs(cards, times+1, least, path, res);
path.pop_back();
for(int i=first; i<=first+4; i++)
cards[i]++;
}
}
// 出连对
if(first+2<cards.size()){
if(cards[first]>=2 && cards[first+1]>=2&&cards[first+2]>=2){
for(int i=first; i<=first+2; i++)
cards[i]-=2;
path.push_back(vector<int> {first, first,first+1, first+1,first+2,first+2});
dfs(cards, times+1, least,path, res);
path.pop_back();
for(int i=first; i<=first+2; i++)
cards[i]+=2;
}
}
}
int main() {
vector<int> cards(10,0);
for(int i=0;i<10;i++)
cin>>cards[i];
int least=INT_MAX;
vector<vector<int>> res;
vector<vector<int>> path;
dfs(cards, 0, least, path, res);
cout<<least<<endl;
for(int i=0;i<res.size();i++)
{
for(int j=0;j<res[i].size(); j++)
cout<<res[i][j]<<',';
cout<<endl;
}
return 0;
}