2020: Card Hand Sorting
Submit Page Summary Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 44 Solved: 19Description
When dealt cards in the card game Plump it is a good idea to start by sorting the cards in hand by suit and rank. The different suits should be grouped and the ranks should be sorted within each suit. But the order of the suits does not matter and within each suit, the cards may be sorted in either ascending or descending order on rank. It is allowed for some suits to be sorted in ascending order and others in descending order. Sorting is done by moving one card at a time from its current position to a new position in the hand, at the start, end, or in between two adjacent cards. What is the smallest number of moves required to sort a given hand of cards?
Input
There will be several test cases. For the each case, the first line of input contains an integer n (1 ≤ n ≤ 52), the number of cards in the hand. The second line contains n pairwise distinct space-separated cards, each represented by two characters. The first character of a card represents the rank and is either a digit from 2 to 9 or one of the letters T, J, Q, K, and A representing Ten, Jack, Queen, King and Ace, respectively, given here in increasing order. The second character of a card is from the set {s, h, d, c} representing the suits spades ♠, hearts ♥, diamonds ♦, and clubs ♣.
Output
Output the minimum number of card moves required to sort the hand as described above.
Sample Input
4 2h Th 8c Qh 7 9d As 2s Qd 2c Jd 8h 4 2h 3h 9c 8c
Sample Output
1 2 0
Hint
Source
对于每种排列方式,固定了花色顺序和每种花色内部的递增减,也就确定了最后的时候每个位置应该放置哪一张牌,也即知道了每张牌最后所在的位置。如果我们把每张牌最后位置按照小到大的顺序排了,那么也就自然的满足了题目的摆放要求。那么可以考虑把这个最后的摆放位置作为每个牌新的权值标号,然后对这个标号求LIS,总的牌数n-LIS即为最后移动的次数。具体见代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define N 110
using namespace std;
int n,m,len,dp[N],order[5],a[N],ans;
struct card{char id,kind;} c[N];
map<char,int> mp;
bool v[5],d[5];
void init() //对每张牌进行重标号,这个号就是可以对应最后的位置,但是有放大
{
len=0;
for(int i=1;i<=n;i++)
if (d[mp[c[i].kind]]) a[i]=(order[mp[c[i].kind]]-1)*20+mp[c[i].id];
else a[i]=order[mp[c[i].kind]]*20-mp[c[i].id];
}
void DP() //直接求LIS
{
dp[++len]=a[1];
for(int i=2;i<=n;i++)
{
if (a[i]>=dp[len]) dp[++len]=a[i];
else
{
int j=lower_bound(dp+1,dp+1+len,a[i])-dp;
dp[j]=a[i];
}
}
ans=min(ans,n-len);
}
void dfs(int dep) //暴力枚举花色顺序和内部递增减
{
if (dep>4)
{
init(); DP();
return;
}
for(int i=1;i<=4;i++)
{
if (v[i]) continue;
order[i]=dep; v[i]=1; d[i]=1; //d[]表示某张牌是递增还是递减
dfs(dep+1); d[i]=0;
dfs(dep+1); v[i]=0;
}
}
int main()
{
mp['s']=1;mp['h']=2;mp['d']=3;
mp['c']=4;mp['T']=10;mp['J']=11;
mp['Q']=12;mp['K']=13;mp['A']=14;
for(int i=2;i<=9;i++) mp[char(i+48)]=i;
while(cin>>n)
{
char x;
getchar();
ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
scanf("%c%c%c",&c[i].id,&c[i].kind,&x);
dfs(1); printf("%d\n",ans);
}
return 0;
}