阿里巴巴笔试题-扑克牌

题目描述:

今天小强从一副扑克牌里拿出来一叠,其中包括A,2,3,...,10各四张,其中A代表1.他从这一叠中抽出一些牌给小明,并告诉小明,每次可以啊按照下列方式打出一些牌。

单牌:一张牌,例如3

对子:数字相同的两张牌,例如77

顺子:数字连续的五张牌,例如A2345

连对:数字连续的三个对子,例如334455

现在小强想知道最少可以打出多少次牌可以打光手中的牌。

输入描述:

一行十个空格分隔的整数A_{1},A_{2},...,A_{10},分别代表牌为A,2,3,...,10的个数。0<=A_{1},A_{2},...,A_{10}<=4,数据保证手上至少有一张牌。

输出描述:

仅一行一个整数表示答案。

输入:

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值