【codevs2451】互不侵犯
今天心情--,连续两次失利
作为今天考试的t2,浪费了太多时间,还没有做出正解
考完试反思,虽然这是第一次在考场上做状压dp,但是这个题并非不可做,而且部分分也很多
从这个题看出,状压有点时候会需要预处理处所有状态
教训:先看一遍所有的题,先打暴力
#include<iostream> #include<cstdio> using namespace std; typedef long long lo; lo n,k1,tot,dp[10][100][550],cnt[550],sy[550],ans; bool mmp[110][110]; void dfs(lo k,lo wei,lo pos) { cnt[++tot]=k,sy[tot]=pos;//新纪录一种答案 if(k>=(n+1)/2||k>=k1)//如果k这个值即将超过限定最多所放的棋子数,或者这行棋子数超过(n+1)/2 ,也就是说有的棋子挨着 return;//即返回 for(int i=wei+2;i<=n;i++)//枚举下一个棋子位置,至少要给棋子之间留一个空 dfs(k+1,i,pos+(1<<(i-1))); } inline void yu() { dfs(0,-1,0);//深搜预处理状态 for(int i=1;i<=tot;i++)//枚举状态,判断是否可以挨着 for(int j=i;j<=tot;j++) mmp[i][j]=mmp[j][i]=((sy[i]&sy[j])||(sy[i]<<1)&sy[j]||(sy[i]>>1)&sy[j])?0:1; for(int i=1;i<=tot;i++) dp[1][cnt[i]][i]=1;//初始化 } int main() { scanf("%lld%lld",&n,&k1); yu();//预处理 for(int i=2;i<=n;i++)//枚举行 for(int j=0;j<=k1;j++)//枚举放置棋子个数 for(int k=1;k<=tot;k++)//枚举现在这行状态 { if(cnt[k]>j) continue; for(int l=1;l<=tot;l++)//枚举上一行的状态 if(cnt[k]+cnt[l]<=j&&mmp[k][l])//如果这两行状态不重复且棋子数未超过限制 dp[i][j][k]+=dp[i-1][j-cnt[k]][l]; } for(int i=1;i<=tot;i++) ans+=dp[n][k1][i];//答案在最后一行所有的状态里 cout<<ans; }