1. 程式人生 > >牛客網多校訓練 德瑪西亞萬歲

牛客網多校訓練 德瑪西亞萬歲

while 關系 out iostream 整數 戰鬥 來源 示例 -m

題目描述 來源

德瑪西亞是一個實力雄厚、奉公守法的國家,有著功勛卓著的光榮軍史。 這裏非常重視正義、榮耀、職責的意識形態,這裏的人民為此感到強烈自豪。 有一天他們想去制裁邪惡的比爾吉沃特,於是派遣了自己最優秀的戰士。 結果比爾吉沃特領土太小,只有長為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; }

牛客網多校訓練 德瑪西亞萬歲