SPOJ 4053 - Card Sorting 最长不下降子序列

我们的男主现在手中有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;

}

 

你可能感兴趣的:(sort)