POJ 1745 Divisibility 类似0-1背包DP

类似背包DP。

用dp[i][j](bool类型)来表示前i个数组成的和对k取模的值是否存在;

状态转移方程为:

if(dp[i-1][j])dp[i][get(tmp-j)]=dp[i][get(tmp+j)]=1;//get:自己写个取模函数,注意负数取模-5%7=2

AC代码:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
bool dp[10003][103];
int k;
int get(int x)
{
    return x < 0 ? -x%k: x%k;
}
int main()
{
    int n,tmp, i, j;
    while(~scanf("%d%d",&n,&k))
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&tmp);
        dp[1][get(tmp)]=1;
        for(i=2;i<=n;i++)
        {
            scanf("%d",&tmp);
            for(j=0;j<k;j++)
            if(dp[i-1][j])dp[i][get(tmp-j)]=dp[i][get(tmp+j)]=1;
        }
        if(dp[n][0])printf("Divisible\n");
        else printf("Not divisible\n");
    }
    return 0;
}

 

 

滚动数组版,节省内存(第一次用,不错):

 

状态转移方程为:

for(j=0;j<k;j++)if(dp[g1][j])dp[g2][get(j-tmp)]=dp[g2][get(j+tmp)]=1;//g1,g2表示两种状态

 

AC代码:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
bool dp[2][103];
int n, k;
int get(int x)
{
    return x < 0 ? -x%k : x%k;
}
int main()
{
    int tmp, i, j;
    while(~scanf("%d%d",&n,&k))
    {
        int g1=0,g2=1;
        memset(dp,0,sizeof(dp));
        scanf("%d",&tmp);
        dp[0][get(tmp)]=1;
        for(i=2;i<=n;i++)
        {
            scanf("%d",&tmp);
            for(j=0;j<k;j++)//注意将状态g2先清零
            dp[g2][j]=0;
            for(j=0;j<k;j++)
            if(dp[g1][j])dp[g2][get(j-tmp)]=dp[g2][get(j+tmp)]=1;
            g1=!g1;g2=!g2;
        }
           if(dp[g1][0])printf("Divisible\n");
        else printf("Not divisible\n");
    }
    return 0;
}

 

 

posted @ 2012-08-05 22:54  To be an ACMan  Views(219)  Comments(0)    收藏  举报