题目:转送门
这题用动态规划做,这动态规划可真够复杂的。
总结我网上看到的资料:
1,由于列数较少,所以以行为动态规划过程的一个状态。
2,每行的炮兵状态也可以统计出来,用status[i]表示第i个状态,status_[i]表示第i个状态的炮兵部队数。
3,状态转移方程:dp[r][i][j]=max{dp[r-1][j][k]+status_num[i]};
dp[r][i][j]表示第r行状态为i,第r-1行状态为j的时候最大炮兵部队数。遍历k状态,并保证i,j,k不冲突。
为什么要dp[r][i][j]而不是dp[r][i]呢?
若用dp[r][i],那状态转移方程为:dp[r][i]=max{dp[r-1][j]+status_num[i]},可是这样子的话,就不能保证第r行与第r-2行的状态不冲突了。
001.
#include <iostream>
002.
#include <string.h>
003.
using
namespace
std;
004.
005.
#define max(a,b) ((a)>(b)?(a):(b))
006.
int
dp[102][65][65];
//dp值,记录某一行相应状态下的最大炮兵数
007.
int
status[65];
//一行中,所有不冲突炮兵部队状态数
008.
int
status_num[65];
//对应于一种炮兵部队状态的炮兵部队数
009.
int
map[102];
//对地形的状态压缩
010.
011.
int
main()
012.
{
013.
int
t,row,col;
014.
char
tmp;
015.
cin>>t;
016.
while
(t--)
017.
{
018.
memset
(map,0,
sizeof
(map));
019.
memset
(dp,0,
sizeof
(dp));
020.
memset
(status,0,
sizeof
(status));
021.
memset
(status_num,0,
sizeof
(status_num));
022.
cin>>row>>col;
023.
//输入地形,用1表示高山,0表示平原
024.
for
(
int
i=1;i<=row;i++)
025.
{
026.
for
(
int
j=0;j<col;j++)
027.
{
028.
cin>>tmp;
029.
if
(tmp==
'H'
)
030.
map[i]|=1<<j;
031.
}
032.
}
033.
if
(row==0)
034.
{
035.
cout<<
'0'
<<endl;
036.
continue
;
037.
}
038.
//统计一行所有可能的满足条件的炮兵部队状态及相应的炮兵部队数
039.
int
sum=0;
040.
for
(
int
i=0;i<(1<<col);i++)
041.
{
042.
if
(i&(i<<1)||i&(i<<2))
043.
continue
;
044.
int
count=0,x=i;
045.
while
(x)
046.
{
047.
count++;
048.
x&=(x-1);
049.
}
050.
status[sum]=i;
051.
status_num[sum++]=count;
052.
}
053.
//状态转移方程:dp[r][i][j]=max(dp[r-1][j][k]+status[i])
054.
//dp[r][i][j], 表示第r行的状态为i,第r-1状态为j,这种情况下的最大炮兵数
055.
//处理第1行
056.
for
(
int
i=0;i<sum;i++)
057.
{
058.
if
(status[i]&map[1])
//与地形有冲突
059.
continue
;
060.
dp[1][i][0]=status_num[i];
061.
}
062.
//处理第2行
063.
for
(
int
i=0;i<sum;i++)
064.
{
065.
if
(status[i]&map[2])
//与地形有冲突
066.
continue
;
067.
for
(
int
j=0;j<sum;j++)
//检验是否与第1行有冲突
068.
{
069.
if
(status[j]&map[1])
//寻找第1行不与地形冲突的状态
070.
continue
;
071.
if
(status[i]&status[j])
//判断第2行是否与第1行冲突
072.
continue
;
073.
dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+status_num[i]);
074.
}
075.
}
076.
//处理之后的行
077.
for
(
int
r=3;r<=row;r++)
078.
{
079.
for
(
int
i=0;i<sum;i++)
//寻找第r行的状态
080.
{
081.
if
(status[i]&map[r])
//检验是否与地形冲突
082.
continue
;
083.
for
(
int
j=0;j<sum;j++)
//寻找第r-1行的状态
084.
{
085.
if
(status[j]&map[r-1])
//检验是否与地形冲突
086.
continue
;
087.
if
(status[i]&status[j])
//检验第r-1是否与第r冲突
088.
continue
;
089.
for
(
int
k=0;k<sum;k++)
090.
{
091.
if
(status[k]&map[r-2])
//检验是否与地形冲突
092.
continue
;
093.
if
((status[i]&status[k])||(status[j]&status[k]))
//检验第r-2是否与第r、r-1冲突
094.
continue
;
095.
dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+status_num[i]);
096.
}
097.
}
098.
}
099.
}
100.
101.
int
max_num=0;
102.
for
(
int
i=0;i<sum;i++)
103.
for
(
int
j=0;j<sum;j++)
104.
if
(dp[row][i][j]>max_num)
105.
max_num=dp[row][i][j];
106.
cout<<max_num<<endl;
107.
}
108.
return
0;
109.
}
参考:http://blog.csdn.net/hearthougan/article/details/21374473