1. 程式人生 > >2018年全國多校算法寒假訓練營練習比賽(第二場)F - 德瑪西亞萬歲

2018年全國多校算法寒假訓練營練習比賽(第二場)F - 德瑪西亞萬歲

code 訓練營 比賽 最優 weight -o com 英雄 tin

鏈接:https://www.nowcoder.com/acm/contest/74/F
來源:牛客網

題目描述

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

題解

狀壓$dp$。

$dp[i][j][k]$表示到第$i$層,放置了$j$個人,且第$i$層的放置狀態為$k$的方案數。

有很多優化可以做,沒做優化也可以過。

#include <bits/stdc++.h>
using namespace std;

int n, m;
int a[20][20];
int h[20];

long long dp[15][80][4100];
long long mod = 100000000LL;
int cnt[4100], error[4100];

int limit = 75;

int lowbit(int x) {
  return x & (-x);
}

void init() {
  for(int i = 1; i < (1 << 12); i ++) {
    cnt[i] = cnt[i - lowbit(i)] + 1;
  }
  for(int i = 0; i < (1 << 12); i ++) {
    for(int j = 0; j < 12; j ++) {
      int A = i & (1 << j);
      int B = i & (1 << (j + 1));
      if(A && B) error[i] = 1;
    }
  }
}

int main() {
  init();
  while(~scanf("%d%d", &n, &m)) {
    for(int i = 1; i <= n; i ++) {
      h[i] = 0;
      for(int j = 0; j < m; j ++) {
        scanf("%d", &a[i][j]);
        h[i] = h[i] * 2 + a[i][j];
      }
    }
    
    dp[0][0][0] = 1;
    for(int i = 1; i <= n; i ++) {
      for(int num = 0; num <= limit; num ++) {
        for(int now = 0; now < (1 << m); now ++) {
          dp[i][num][now] = 0;
          if(error[now]) continue;
          if((now | h[i]) != h[i]) continue;
          if(num - cnt[now] < 0) continue;
          
          for(int pre = 0; pre < (1 << m); pre ++) {
            if(error[now]) continue;
            if(pre & now) continue;
            dp[i][num][now] = (dp[i][num][now]
                               + dp[i - 1][num - cnt[now]][pre]) % mod;
          }
        }
      }
    }
    long long ans = 0;
    for(int num = 0; num <= limit; num ++) {
      for(int now = 0; now < (1 << m); now ++) {
        ans = (ans + dp[n][num][now]) % mod;
      }
    }
    printf("%lld\n", ans);
    
  }
  return 0;
}

2018年全國多校算法寒假訓練營練習比賽(第二場)F - 德瑪西亞萬歲