这个也只麻烦一点点而已,与easy version不同的地方在于允许3张连续的牌出现
进行这种判断只需要进行一遍DFS就行了
关键在于DFS的细节:
如果一张牌出现【超过或等于】3次,他都有可能凑成一个3张相同的坎牌,但也有可能不
如果一张牌出现【超过或等于】2次,他都有可能凑成一个对牌,但也有可能不
如果一张牌出现【超过或等于】1次,他都有可能凑成一个3张连续的坎牌,但也有可能不
如果一张牌出现【只有】1次,他【只可能】凑成一个3张连续的坎牌
所以在DFS实现过程中,我们要把每种情况尝试一遍,统计坎牌和对牌的出现次数
有一个特例:
1W1W2W2W3W3W4W4W5T6T6T7T7T8T
这里的1W2W3W4W四张牌均有2个相同,他们既有可能作为坎牌也有可能作为对牌
遇到这种情况,我们从小到大遍历时,优先考虑坎牌的情况(一点点贪心?不证明了,但应该是对的。)
核心代码用伪代码表示大概是
pair<int, int> get(int num[]) { int cnt2 = 0, cnt3 = 0, sum = 0; for(int i = 1; i <= 29; ++i) sum += num[i]; for(int i = 1; i <= 29; ++i) { if(!num[i]) continue; switch(num[i]) { case 4: case 3: 尝试用3张相同的牌作为坎牌 case 2: { if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) { 尝试用3张连续的牌作为坎牌 } 尝试用2张相同的牌作为对牌 break; } case 1: { if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) { 尝试用3张连续的牌作为坎牌 } else return make_pair(0, 0); } } } return make_pair(0, 0); }
然后是完整代码
#include<bits/stdc++.h> using namespace std; int getId(char num, char type) { if(type == 'W') return num - '0'; if(type == 'T') return num - '0' + 10; else return num - '0' + 20; } bool judge(int id, char type) { if(1 <= id && id <= 9 && type == 'W') return true; if(11 <= id && id <= 19 && type == 'T') return true; if(21 <= id && id <= 29 && type == 'S') return true; return false; } map<int, int> mp; pair<int, int> get(int num[]) { int cnt2 = 0, cnt3 = 0, sum = 0; for(int i = 1; i <= 29; ++i) sum += num[i]; for(int i = 1; i <= 29; ++i) { if(!num[i]) continue; switch(num[i]) { case 4: case 3: { num[i] -= 3; ++cnt3; pair<int, int> pr = get(num); cnt2 += pr.first; cnt3 += pr.second; if(2*cnt2 + 3*cnt3 == sum) return make_pair(cnt2, cnt3); cnt2 -= pr.first; cnt3 -= pr.second; num[i] += 3; --cnt3; } case 2: { if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) { --num[i]; --num[i+1]; --num[i+2]; ++cnt3; pair<int, int> pr = get(num); cnt2 += pr.first; cnt3 += pr.second; if(2*cnt2 + 3*cnt3 == sum) return make_pair(cnt2, cnt3); cnt2 -= pr.first; cnt3 -= pr.second; ++num[i]; ++num[i+1]; ++num[i+2]; --cnt3; } num[i] -= 2; ++cnt2; pair<int, int> pr = get(num); cnt2 += pr.first; cnt3 += pr.second; if(2*cnt2 + 3*cnt3 == sum) return make_pair(cnt2, cnt3); cnt2 -= pr.first; cnt3 -= pr.second; num[i] += 2; --cnt2; break; } case 1: { if(i < 28 && num[i+1] >= 1 && num[i+2] >= 1) { --num[i]; --num[i+1]; --num[i+2]; ++cnt3; pair<int, int> pr = get(num); cnt2 += pr.first; cnt3 += pr.second; if(2*cnt2 + 3*cnt3 == sum) return make_pair(cnt2, cnt3); cnt2 -= pr.first; cnt3 -= pr.second; ++num[i]; ++num[i+1]; ++num[i+2]; --cnt3; } else return make_pair(0, 0); } } } return make_pair(0, 0); } pair<int, int> judge() { int num[30]; memset(num, 0, sizeof(num)); for(int i = 1; i <= 29; ++i) num[i] = mp[i]; pair<int, int> ans = get(num); return ans; } void printMap() { printf("=============\n"); for(auto it = mp.begin(); it != mp.end(); ++it) printf("%d->%d\n", it->first, it->second); printf("=============\n"); } int main() { int n; while(cin>>n) { char que; cin>>que; while(n--) { mp.clear(); bool mark = true; char pai[50]; cin>>pai; for(int i = 0; i < 14; ++i) { int id = getId(pai[i*2], pai[i*2 + 1]); if(judge(id, que)) { mark = false; break; } mp[id]++; } if(mark) { pair<int, int> pr = judge(); int cnt2 = pr.first; int cnt3 = pr.second; if(!(cnt2 == 7 || (cnt2 == 1 && cnt3 == 4))) mark = false; } printf(mark ? "Yes\n" : "No\n"); } } return 0; }