题意:给你一列整数,在整数间加‘ + ’ 或 ‘ - ‘,使这个算式的值能被k整除。
用dp[ i ][ j ] 表示加上或减去第 i 个数后,所得值取模后的值能否为 j ,所以dp为bool型即可。
状态转移方程:dp[ i ][ abs( j + num[i]) % k] = true;
dp[ i ][ abs( j - num[i]) % k] = true; (当然,必须满足dp[ i - 1 ][ j ] == true, 才能进行状态转移)
边界条件:dp[ 0 ][ 0 ] = true;
时间效率不高:235ms 不知道大牛的0ms怎么做出来的
#include <iostream>
#include <cmath>
using namespace std;
#define N 10002
#define K 102
int num[N], n, k;
bool dp[N][K];
void Init()
{
int i;
scanf("%d%d", &n, &k);
for(i = 1; i <= n; i++)
scanf("%d", &num[i]);
}
bool Solve()
{
int i, j;
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for(i = 1; i <= n; i++){
for(j = 0; j < k; j++){
if(dp[i-1][j]){
dp[i][abs(j + num[i]) % k] = true;
dp[i][abs(j - num[i]) % k] = true;
}
}
}
return dp[n][0];
}
int main()
{
Init();
if(Solve())
printf("Divisible\n");
else
printf("Not divisible\n");
return 0;
}
发现别人的内存很小,一看状态转移方程,当前行只与上一行的值有关,原来可以开滚动数组。219ms
#include <iostream>
#include <cmath>
using namespace std;
#define N 10002
#define K 102
int num[N], n, k;
bool dp[2][K];
void Init()
{
int i;
scanf("%d%d", &n, &k);
for(i = 1; i <= n; i++)
scanf("%d", &num[i]);
}
bool Solve()
{
int i, j;
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for(i = 1; i <= n; i++){
for(j = 0; j < k; j++) // 开滚动数组之后与之前代码的不同之处,必须对当前正在处理的
dp[i%2][j] = false;// 第i行重新赋值为false,避免之前得到的值对当前造成影响
for(j = 0; j < k; j++){
if(dp[1-i%2][j]){
dp[i%2][abs(j + num[i]) % k] = true;
dp[i%2][abs(j - num[i]) % k] = true;
}
}
}
return dp[n%2][0];
}
int main()
{
Init();
if(Solve())
printf("Divisible\n");
else
printf("Not divisible\n");
return 0;
}