前天把状态压缩彻底弄明白啦,哈哈!昨天和今天写了两道状态压缩题,高兴啊!今天开始做树形dp,感觉和前天刚解除状态压缩一样,嘿嘿,都是会解决的啦!这两天校运会,感觉比上课都累啊!而且只有晚上看题,保持一晚上一道题,收获不小啊!
这道题是典型的状态压缩dp,不过注意一下优化:
空间优化:对于那些本来就不符合的状态就不要记录了,不然会超内存的!
时间优化:对于上面两行组成的状态不成立的直接进行下一个循环,不用浪费时间!
下面是我的代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<climits>
using namespace std;
#define rep(i,n) for(i=0; i<(n); i++)
#define reph(i,n,m) for(i=(n); i<=(m); i++)//正循环的
#define repd(i,n,m) for(i=(n); i>=(m); i--) //负循环的
#define max(a,b) (a)>(b)?(a):(b)
#define fab(a) (a)>0?(a):0-(a)
#define ll long long
#define arc(a) (a)*(a)
#define inf 100000000 //最大值的
#define exp 0.0000001 //浮点型的
#define N 10 //记录开的数组
int f[105];
int dp[105][100][100];
int a[105];//记录满足最基本题意的解的
bool fun(int a,int m)
{
int i=0;
int x=-(m+1);
while(a!=0)
{
if(a%2==1)
{
if(i-x<(m+1))
return true; //代表不满足题意的
x=i;
}
i++;
a=a>>1;
}
return false;
}
bool panduan(int a,int b,int c)
{
if((a&c)!=0 || (b& c)!=0)
return false;//就是有相同的点的
return true;
}
int find(int a)
{
int sum=0;
while(a!=0)
{
if(a%2==1)
sum++;
a=a>>1;
}
return sum;
}
int main()
{
int n,m,i,j,k,l,r;
char s[15];
while(scanf("%d%d",&n,&m)!=EOF)
{
reph(i,1,n)
{
scanf("%s",s);
f[i]=0;
reph(j,0,m-1)
{
f[i]=f[i]<<1;
if(s[j]=='P')
f[i]+=1;
}
}
memset(dp,0,sizeof(dp));
r=1<<m;
j=0;//记录满足题意的解的
reph(i,0,r-1)
if(!fun(i,2))//满足两个站点之间的间隔为2的,任何两个炮兵部队不能相互攻击的
a[j++]=i;//记录的
r=j;//从0到r-1的
reph(i,1,n)
{
reph(j,0,r-1)
{
if((a[j]&f[i])!=a[j])//不存在a【j】这种情况的
continue;
reph(k,0,r-1)
reph(l,0,r-1)
{
if((a[k] & a[l])!=0)//k和l这种情况就不存在的
continue;
if(panduan(a[k],a[l],a[j]))
dp[i][l][j]=max(dp[i][l][j],dp[i-1][k][l]+find(a[j]));
}
}
}
int Max=0;
reph(i,0,r-1)
reph(j,0,r-1)
Max=max(Max,dp[n][i][j]);
printf("%d\n",Max);
}
return 0;
}