标签:例如 101101 互不侵犯 int P1896 num SCOI2005 dp 101001
这题主要分两个步骤:
Section A:
初始化每一行中国王互相不攻击的情况
Section B:
考虑列和列之间国王不攻击。
解释都在代码里:
#include<bits/stdc++.h>
#define N 15//行数
#define M 1050//状态数
#define K 105//国王数
#define rd(x) x=read()
using namespace std;
typedef long long ll;
ll dp[N][M][K];
int n,m,cnt=0;
struct node
{
int s;
int num;//1的个数,1代表国王放置
}st[M];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void init()//预处理出每行的合法状态
{
int totS=(1<<n);
for(int s=0;s<totS;s++)
{
if(s&(s<<1))continue;//存在1相邻
int num=0;
for(int i=0;i<n;i++)if(s&(1<<i))num++;//统计1的个数
if(num>m)continue;//1的个数超限
st[cnt].s=s,st[cnt++].num=num;//加入状态
}
}
void solve()
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int i=1;i<=n;i++)//枚举行
for(int j=0;j<cnt;j++)//枚举第i行状态
for(int l=0;l<cnt;l++)
{
if(st[j].s&st[l].s)continue;//上一行同列冲突
if(st[j].s&(st[l].s<<1))continue;//上一行右上角冲突
if(st[j].s&(st[l].s>>1))continue;//上一行左上角冲突
for(int k=st[j].num;k<=m;k++)
dp[i][j][k]+=dp[i-1][l][k-st[j].num];
}
}
int main()
{
rd(n),rd(m);
init(),solve();
ll ans=0;
for(int i=0;i<cnt;i++)ans+=dp[n][i][m];
printf("%lld\n",ans);
return 0;
}
附录:
因为这是一道状压DP的模板题
而状压DP需要足够的位运算基础以减少代码量
这里给出常用的位运算操作(共19个)
1、去掉最后一位 例如:101101->10110
2、在最后加一个0 例如:101101->1011010
3、在最后面加一个1 例如:101101->1011011
4、把最后一位变成0 例如:101101->101100
5、把最后一位变成1 例如:101100->101101
6、最后一位取反 例如:101101->101100
7、把右数第k位变成1 例如:101001->101101,k=3
8、把右数第k位变成0 例如:101101->101001,k=3
9、右数第k位取反 例如:101001->101101,k=3
10、取末三位 例如:1101101->101
11、取末k位 例如:1101101->1101,k=4
12、取右数第k位 例如:1101101->1,k=4
13、把末尾k位变成1 例如:101001->101111,k=4
14、末k位取反 例如:101001->100110,k=4
15、把右边连续的1变成0 例如:100101111->100100000
16、把右边起第一个0变成1 例如:100101111->100111111
17、把右边起连续的0变成1 例如:110011000->110011111
18、取右边连续的1 例如:100101111->1111
19、去掉右边起第一个1的左边 例如:100101000->1000
code:
if(opt==1)x>>=1;//右移一位
else if(opt==2)x<<=1;//左移一位
else if(opt==3)x<<=1,x|=1;//左移一位+1
else if(opt==4)x|=1,x--;//强制把最后一位变为1后-1(这样就变为0呀)
else if(opt==5)x|=1;//变为1
else if(opt==6)x^=1;//1=0000……0001,异或时前面都不变,最后一位取反
else if(opt==7){scanf("%d",&k);x|=(1<<(k-1));}
else if(opt==8){scanf("%d",&k);x|=(1<<(k-1)),x-=(1<<(k-1));}
else if(opt==9){scanf("%d",&k);x^=(1<<(k-1));} //以上操作跟前面类似
else if(opt==10)x%=8;
else if(opt==11){scanf("%d",&k);x%=(1<<k);}//取模得后k位
else if(opt==12){scanf("%d",&k);x&=((1<<(k-1)));x=x?1:0;}//如果结果不为0,那么那一位就为1
else if(opt==13){scanf("%d",&k);x|=((1<<k)-1);}
else if(opt==14){scanf("%d",&k);x^=((1<<k)-1);}//以上操作跟前面类似
else if(opt==15)x&=(x+1);
else if(opt==16)x|=(x+1);
else if(opt==17)x|=(x-1);
else if(opt==18)x++,x&=(-x),x--;
else x&=(-x);
标签:例如,101101,互不侵犯,int,P1896,num,SCOI2005,dp,101001
来源: https://www.cnblogs.com/Robin20050901/p/10786065.html
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。