牛客网多校训练 德玛西亚万岁
题目描述 来源
德玛西亚是一个实力雄厚、奉公守法的国家,有着功勋卓著的光荣军史。
这里非常重视正义、荣耀、职责的意识形态,这里的人民为此感到强烈自豪。
有一天他们想去制裁邪恶的比尔吉沃特,于是派遣了自己最优秀的战士。
结果比尔吉沃特领土太小,只有长为n宽为m共计n*m块土地,其中有些土
地标记为0表示为高山峻岭或者深海湖泊,英雄们无法在其中站立,只有标
记为1的土地才能容纳一个英雄。德玛西亚的英雄们战斗时有一个特点,他
们不希望队友站在自己旁边显得很暧昧。请问最多能有多少种安排德玛西
亚英雄的方法?
输入描述:
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 12, m <= 12 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的比尔吉沃特领土。
输出描述:
输出一个整数n代表安排应用的方法。
(答案取膜100000000)
示例1
输入
3 3 1 1 1 0 1 1 1 0 0
输出
24
总结
1.使用状态压缩,逐行枚举
2.进行位运算一定不能吝啬括号,因为位运算的优先级实在是太低了
3.因为m,n的范围很小,所以使用一些复杂度高的算法也没什么关系的
#include <cstdio> #include <iostream> #include <cstdlib> #include <cstring> using namespace std; #define INF 0x3f3f3f3f//可以用于memset int map[13];//map[i]第i行的状态 long long dp[13][1<<12];//dp[i][j],第1到第i行,并且第i行状态为j时,的安排方法 int isok[1<<12];//isok[i]指第i个不相邻站立的状态,以后就枚举这些状态 int main() { int n,m,k;long long ans; while(cin>>n>>m) { memset(dp,0,sizeof(dp)); memset(map,0,sizeof(map)); ans=0; for(int i=1;i<=n;i++) { for(int j=m-1;j>=0;j--) { cin>>k; if(k==1) map[i]+=(1<<(j)); } } int len=1<<m;int num=0; for(int i=0;i<len;i++)//初始化第一行 { if((i&(i<<1))==0) { isok[num++]=i; if((i|map[1])==map[1]) { dp[1][i]=1; } } } for(int i=2;i<=n;i++) { for(int j=0;j<num;j++) { int a1=isok[j]; if((a1|map[i])==map[i]) for(int k=0;k<num;k++) { int a2=isok[k]; if((a2&a1)==0) dp[i][a1]+=dp[i-1][a2]; } } } for(int i=0;i<num;i++) { ans+=dp[n][isok[i]]; ans%=100000000; } cout<<ans<<endl; } return 0; }