我们的男主现在手中有n*c张牌,其中有c(<=4)种颜色,每种颜色有n(<=100)张,现在他要排序,首先把相同的颜色的牌放在一起,颜色相同的按照序号从小到大排序。现在他想要让牌的移动次数最小,问移动的最小次数是多少。
【LIS】因为颜色种类相当少,可以枚举排序后颜色的次序。相同颜色的纸牌从小到大排序,所以所有纸牌的最终顺序也就确定了。
然后就是怎么样移动纸牌能够使纸牌成为最终的顺序。
因为从给定序到有序的移动次数等于从有序到给定序,所以我们反着想,对于有序的序列,移动一张纸牌,那么它的最长不降序列就减少1。如果移动多个呢,只要求出其中没有改变的最大长度即可,这个长度就是原序列的最长不降序列。
一般的,如果给定序的最长不降序列是x,那么到有序状态的移动次数一定是n*c-x
#include<bits/stdc++.h> #define eps 1e-9 #define FOR(i,j,k) for(int i=j;i<=k;i++) #define MAXN 1005 #define MAXM 40005 #define INF 0x3fffffff using namespace std; typedef long long LL; struct node { int c,w,hash; }p[505]; int i,j,k,n,m,x,y,T,ans,big,cas,num,len; bool flag; int ord[5],c; bool vis[5]; bool cmp(node a,node b) { return a.hash<b.hash; } void work() { for (int i=1;i<=n*c;i++) { p[i].hash=ord[p[i].c]*1000+p[i].w;//给每个元素一个唯一标识,按照这个标识来求最长不下降子序列 } int dp[505],num; dp[0]=0; num=0; for (int i=1;i<=n*c;i++) { if (p[i].hash>=dp[num]) { dp[++num]=p[i].hash; }else { k=upper_bound(dp+1,dp+1+num,p[i].hash)-dp; dp[k]=p[i].hash; } } ans=min(ans,n*c-num); } void dfs(int f) { for (int i=1;i<=c;i++) { if (!vis[i]) { vis[i]=1; ord[f]=i; if (f==c) work();else dfs(f+1);//枚举完毕后进入work()计算最长不下降子序列 vis[i]=0; } } } int main() { scanf("%d%d",&c,&n); ans=INF; for (i=1;i<=c*n;i++) { scanf("%d%d",&p[i].c,&p[i].w); } memset(vis,0,sizeof(vis)); dfs(1);//DFS枚举颜色次序 printf("%d\n",ans); return 0; }
时间: 2024-11-05 20:36:39