(CSU

来源:互联网 发布:java定时器讲解 编辑:程序博客网 时间:2024/06/14 00:10

(CSU - 1729)齿轮传动

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 204 Solved: 97

Description

你在一家机械厂打工,你的老板让你把一组齿轮种类序列a1,a2,..,an取走几个让齿轮的传动比为1:1,老板要求你取走最少的齿轮,不能改变齿轮原来的相对位置,满足条件,即齿轮种类组合起来是回文串。

Input

多组数据,第一行有一个整数T , 表示有T组数据。(T<=100)
以下每组数据第一行有一个整数n , 表示n个齿轮(1<=n<=1000)
接下来一行有n个整数a1,a2,…,an表示齿轮种类 (1<=ai<=10000)

Output

取走的最少齿轮数

Sample Input

1
4
1 2 3 1

Sample Output

1

思路:有两种方法可以求解,一种是先求出最长回文子序列,然后数字总个数-最长回文子序列就是要求的答案,其中最长回文子序列可以就是一个模板题;还有一种直接dp,设f[i][j]表示区间[i,j]需要删除的数字个数,那么显然可以得到状态转移方程:①a[i]==a[j],f[i][j]=f[i+1][j-1],②a[i]!=a[j],f[i][j]=min(f[i+1][j],f[i][j-1])+1。其中i要从后往前枚举,j要从前往后枚举,因为这样才能保证后面的状态可以由前面的状态推出。

方法一:

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn =1005;int a[maxn],f[maxn][maxn];int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        for(int i=0;i<n;i++) scanf("%d",a+i);        memset(f,0,sizeof(f));        for(int i=n-1;i>=0;i--)        {            f[i][i]=1;            for(int j=i+1;j<=n;j++)            {                if(a[i]==a[j]) f[i][j]=f[i+1][j-1]+2;                else f[i][j]=max(f[i+1][j],f[i][j-1]);            }        }        printf("%d\n",n-f[0][n-1]);    }    return 0;}

方法二:

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn =1005;int a[maxn],f[maxn][maxn];int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        for(int i=0;i<n;i++) scanf("%d",a+i);        memset(f,0,sizeof(f));        for(int i=n-1;i>=0;i--)        {            f[i][i]=0;            for(int j=i+1;j<=n;j++)            {                if(a[i]==a[j]) f[i][j]=f[i+1][j-1];                else f[i][j]=min(f[i+1][j],f[i][j-1])+1;            }        }        printf("%d\n",f[0][n-1]);    }    return 0;}
原创粉丝点击