先做的HDU1565方格取数问题,在格点取数,所取得数不能相邻,问最大能取得总和是多少
容易想到——dp[i][j]表示当前i行j状态所取得数,如何dp呢???
首先针对每一行找到可以通过得方方案(左右不相邻即可——存储到pass_state【】中)
void find_pass()
{
for(int i = 0;i < (1 << N);i++)
{
if((i & (i << 1)))continue;
pass_state[++tot] = i;
}
}
然后针对每一行得每一个可行的状态,要求出其这个状态对应的值得和,方便后续的状态转移求取最大值int array_pass[25][18000];
int get_part_sum(int x,int h)
{
int sum = 0;
for(int i = 0;i < N;i++)
{
if((x & (1 << i)) > 0)
{
sum += cost[h][i];
}
}
return sum;
}
void save_pass_state()
{
for(int i = 1;i <= tot;i++)
{
array_pass[0][i] = dp[0][i] = get_part_sum(pass_state[i],0);
for(int j = 1;j < N;j++)
{
array_pass[j][i] = get_part_sum(pass_state[i],j);
}
}
}
一开始顺便初始化了第一行的dp值,因为第一行特殊,不需要考虑上下相邻得情况
这样我们就可以从第二行开始比——外层一个行循环,往里是当前状态,最里面是上一行的状态,如果满足上下不相邻得情况那就可以尝试状态转移了
void find_return()
{
for(int i = 1;i < N;i++)
{
for(int j = 1;j <= tot;j++)
{
for(int k = 1;k <= tot;k++)
{
if((pass_state[j] & pass_state[k]) > 0)continue;
dp[i][j] = max(dp[i][j],dp[i - 1][k] + array_pass[i][j]);
}
}
}
}
void get_ret()
{
int ret_max = -1;
for(int i = 1;i <= tot;i++)
{
ret_max = max(ret_max,dp[N - 1][i]);
}
printf("%d\n",ret_max);
}
最后的输出是在最后一行的所有可行状态中选出一个最大得输出……
然后看一下Poj3254,其实还真的差不多,只不过这个想让求总的方法数,而且对于可行状态也有了自己的定义不仅仅是不相邻了,其实无非就是在原先的暴力中添加一次筛选,只有满足输入状体的才可以进行下去
依旧是先去寻找可行的不相邻(左右)得状台
void get_ret()
{
int ret_max = -1;
for(int i = 1;i <= tot;i++)
{
ret_max = max(ret_max,dp[N - 1][i]);
}
printf("%d\n",ret_max);
}
然后有了两个判断——一个是判断当前行得状态满不满足输入得状态限制——一个是判断上下想不相邻bool is_pass_mp_state(int state,int line)
{
state = pass_state[state];
for(int i = 0;i < M;i++)
{
if(((mp[line] >> i) & 1) == 0 && ((state >> i) & 1) == 1)
return false;
}
return true;
}
bool is_pass_state_line_by_line(int j,int k)
{
j = pass_state[j];
k = pass_state[k];
for(int i = 0;i < M;i++)
{
if(((j >> i) & 1) == 1 && ((k >> i) & 1 ) == 1)
return false;
}
return true;
}
这样作为dp得基础初始化第一行得值~,并进行层层更新
void init_first_state()
{
for(int i = 1;i <= tot;i++)
{
if(is_pass_mp_state(i,0))
{
dp[0][i] = 1;
}
}
}
void update_layer_upon_layer()
{
for(int i = 1;i < N;i++)
{
for(int j = 1;j <= tot;j++)
{
for(int k = 1;k <= tot;k++)
{
if(is_pass_state_line_by_line(j,k) && is_pass_mp_state(j,i))
{
dp[i][j] += dp[i - 1][k];
}
}
}
}
}
最后的方法总数也就得到了void get_sum()
{
int sum = 0;
for(int i = 1;i <= tot;i++)
{
//cout<<pass_state[i]<<" ###"<<endl;
//cout<<dp[N - 1][i]<<endl;
sum += dp[N - 1][i];
sum %= mod;
}
printf("%d\n",sum);
}
有一个地方没有提到就是对于地图状态得转化0 1 输入还好做,熟练以下位运算就好了for(int i = 0;i < N;i++)
{
for(int j = M - 1;j >= 0;j--)
{
scanf("%d",&num);
if(num)mp[i] += (1 << j);
}
}