题目描述:
今天小强从一副扑克牌里拿出来一叠,其中包括A,2,3,...,10各四张,其中A代表1.他从这一叠中抽出一些牌给小明,并告诉小明,每次可以啊按照下列方式打出一些牌。
单牌:一张牌,例如3
对子:数字相同的两张牌,例如77
顺子:数字连续的五张牌,例如A2345
连对:数字连续的三个对子,例如334455
现在小强想知道最少可以打出多少次牌可以打光手中的牌。
输入描述:
一行十个空格分隔的整数,分别代表牌为A,2,3,...,10的个数。
,数据保证手上至少有一张牌。
输出描述:
仅一行一个整数表示答案。
输入:
1 1 1 2 2 2 2 2 1 1
输出:
3
思路:相信大多数人看到这个题目的第一眼就是暴力搜或者贪心,实际上解法是暴搜(带记忆化)+贪心优化,否则很容易TLE。我们来看几种出牌情况,我们可以发现,如果可以出对子的牌,那么出对子肯定不会比出单牌要花更多步数。同样,可以出顺子的牌,出顺子也不会比出单排花费更多步数。可以出连对的牌,出连队一定不会比出单个对子或者单排花费更少的步数。然而连队和顺子之间没有包含关系,所以我们得到两个出牌优先级:
1.顺子>单排
2.连对>单对>单牌
虽然我们无法确定顺子和连对优先出谁,但是在代码实现上,我们可以将顺子放在连对上,但是即便顺子可以走,我们也不剪掉出连对的可能性,然而如果连对能走,我们就直接不考虑单排和单对的情况了。
代码:
#include<bits/stdc++.h>
using namespace std;
unordered_map<string,int> Dp;
int DFS(string state) {
if (Dp.find(state) != Dp.end())return Dp[state];
int result = 0x7fffffff, i;
for (i = 9; i >= 0; i--) {
if (state[i] > '0') {
if (i > 3 && state[i] > '0' && state[i - 1] > '0' && state[i - 2] > '0' && state[i - 3] > '0' && state[i - 4] > '0') {//有五连顺子
state[i]--;
state[i - 1]--;
state[i - 2]--;
state[i - 3]--;
state[i - 4]--;
result = min(result, DFS(state));
state[i]++;
state[i - 1]++;
state[i - 2]++;
state[i - 3]++;
state[i - 4]++;
}
if (i > 1 && state[i] > '1' && state[i - 1] > '1' && state[i - 2] > '1') {//有三连对
state[i] -= 2;
state[i - 1] -= 2;
state[i - 2] -= 2;
result = min(result, DFS(state));
state[i] += 2;
state[i - 1] += 2;
state[i - 2] += 2;
continue;
}
if (state[i] > '1') {//打对子
state[i] -= 2;
result = min(result, DFS(state));
state[i] += 2;
continue;
}
state[i]--;
result = min(result, DFS(state));
state[i]++;
}
}
return Dp[state] = result + 1;
}
int main() {
string state="0000000000";
Dp[state]=0;
int i,num;
for( i=0; i<10; ++i){
cin >> num;
state[i] += num;
}
cout<< DFS(state);
}
不放心的各位姥爷还可以拿对数器验,下面代码使用了多线程:
#include<iostream>
#include<unordered_map>
#include<vector>
#include<thread>
using namespace std;
const int Num=12;
unordered_map<string,int> *Dp1[Num],*Dp2[Num];
std::vector<std::thread> threadPool;
bool start[Num];
int min(int x, int y) {
if (x > y)return y;
return x;
}
int DFS1(string state, unordered_map<string, int>* Dp1) {
if (Dp1->find(state) != Dp1->end())return (*Dp1)[state];
int result = 0x7fffffff, i;
for (i = 9; i >= 0; i--) {
if (state[i] > '0') {
if (i > 3 && state[i] > '0' && state[i - 1] > '0' && state[i - 2] > '0' && state[i - 3] > '0' && state[i - 4] > '0') {//五连顺子
state[i]--;
state[i - 1]--;
state[i - 2]--;
state[i - 3]--;
state[i - 4]--;
result = min(result, DFS1(state, Dp1));
state[i]++;
state[i - 1]++;
state[i - 2]++;
state[i - 3]++;
state[i - 4]++;
}
if (i > 1 && state[i] > '1' && state[i - 1] > '1' && state[i - 2] > '1') {//三连对
state[i] -= 2;
state[i - 1] -= 2;
state[i - 2] -= 2;
result = min(result, DFS1(state, Dp1));
state[i] += 2;
state[i - 1] += 2;
state[i - 2] += 2;
continue;
}
if (state[i] > '1') {//打对子
state[i] -= 2;
result = min(result, DFS1(state, Dp1));
state[i] += 2;
continue;
}
state[i]--;
result = min(result, DFS1(state, Dp1));
state[i]++;
}
}
return (*Dp1)[state] = result + 1;
}
int DFS2(string state, unordered_map<string, int>* Dp2) {
//cout<<state<<endl;
if (Dp2->find(state) != Dp2->end())return (*Dp2)[state];
int result = 0x7fffffff, i;
for (i = 9; i >= 0; i--) {
if (state[i] > '0') {
if (i > 3 && state[i] > '0' && state[i - 1] > '0' && state[i - 2] > '0' && state[i - 3] > '0' && state[i - 4] > '0') {//五连顺子
state[i]--;
state[i - 1]--;
state[i - 2]--;
state[i - 3]--;
state[i - 4]--;
result = min(result, DFS2(state, Dp2));
state[i]++;
state[i - 1]++;
state[i - 2]++;
state[i - 3]++;
state[i - 4]++;
}
if (i > 1 && state[i] > '1' && state[i - 1] > '1' && state[i - 2] > '1') {//三连对
state[i] -= 2;
state[i - 1] -= 2;
state[i - 2] -= 2;
result = min(result, DFS2(state, Dp2));
state[i] += 2;
state[i - 1] += 2;
state[i - 2] += 2;
}
if (state[i] > '1') {//打对子
state[i] -= 2;
result = min(result, DFS2(state, Dp2));
state[i] += 2;
}
state[i]--;
result = min(result, DFS2(state, Dp2));
state[i]++;
}
}
return (*Dp2)[state] = result + 1;
}
void Judge(int Number, string state) {
if (DFS1(state, Dp1[Number]) != DFS2(state, Dp2[Number])) {
cout << "失败样例:" << state << endl;
}
}
int main() {
int i, cnt, temp, loc;
string state = "0000000000";
threadPoolresize(Num);
for(int i = 0; i < Num; i++)
{
Dp1[i] = new unordered_map<string, int>;
Dp2[i] = new unordered_map<string, int>;
}
for (i = 0; i < 9765625; ++i) {
temp = i;
cnt = 0;
while (temp) {
state[cnt++] = '0' + temp % 5;
temp /= 5;
}
loc=i%Num;
if (start[loc]) {
threadPool[loc].join();
}
Dp1[loc]->clear(); Dp2[loc]->clear();
threadPool[loc] = std::thread(Judge, loc, state);
start[loc] = true;
}
for(i=0;i<Num;++i)threadPool[i].join();
cout << "成功" << endl;
}