CSU 1248: 非变性聚丙烯酰胺凝胶电泳

动规题,方法很巧。很像背包问题,这道题我们可以想成给了空间M,让你求价值之和与M的差最小的那个和,如果超过了M的某个和与小于M的某个和与M之差相等,取小的那个,而我们的方法是将背包空间扩充两倍,初始化f[0][0] = 1;f[i][0] = 0;我们利用01背包的知识求出2M空间的所有值,然后从f[N][j]中以M为中心向两边找,找到第一个为1的f[N][j](如果两边相等取小的),即为所求。(从整个空间开始不断的减少(增加)空间,看最近的哪一个恰好能够装满)。

代码如下:

#include<stdio.h>
#define MAXN 2010
int f[MAXN][MAXN], A[1010];
int M,N;
void solve()
{
    f[0][0] = 1;
    for(int i = 1; i <= 2*M; i ++)
    {
        f[0][i] = 0;
    }
    for(int i = 1; i <= N;i ++)
    {
        for(int j = 0; j <= 2*M; j ++)
        {
            f[i][j] = f[i-1][j];
            if(j >= A[i]) f[i][j] = f[i][j] || f[i-1][j-A[i]];
        }
    }
for(int i = 0;; i ++)
    if(f[N][M - i] || f[N][M + i])
    {
        if(f[N][M - i])
            {printf("%d\n", M - i + 18);}
        else printf("%d\n",M + i + 18);
        break;
    }
}
void input()
{
    while(scanf("%d%d",&N,&M) == 2)
    {
        M -= 18;
        for(int i = 1; i <= N; i ++)
        {
            scanf("%d",&A[i]);
            A[i] -= 18; 
        }
        solve();
    }
}
int main()
{
    input();
    return 0;
}



posted on 2012-04-10 00:45  BFP  阅读(317)  评论(0编辑  收藏  举报