HDU 4539 郑厂长系列故事――排兵布阵(状态压缩)

郑厂长系列故事——排兵布阵

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

Total Submission(s): 1954    Accepted Submission(s): 701

Problem Description

  郑厂长不是正厂长

  也不是副厂长

  他根本就不是厂长

  事实上

  他是带兵打仗的团长

  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。

  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。

  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。

Input

输入包含多组测试数据;

每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;

接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。

Output

请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。

Sample Input

6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

Sample Output

2

题解:

1.曼哈顿距离:两点(x1,y1)(x2,y2)的曼哈顿距离为|x1-x2|+|y1-y2|;

2.假如一个点要安排士兵,我们要考虑的是曼哈顿距离为二的几个点是否会造成冲突,即若(x,y)安排人,则(x-2,y)(x-1,y+1),(x,y+2),(x+1,y+1),(x+2,y),(x+1,y-1),(x,y-2),(x-1,y-1)不能有人。然后就是状态方程了:dp[i][j][k] = Max(d[i][j][k],dp[i
- 1][k][l] + sum[j]);

My Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<map>

#define N 100010
#define Mod 10000007
#define lson l,mid,idx<<1
#define rson mid+1,r,idx<<1|1
#define lc idx<<1
#define rc idx<<1|1
const double EPS = 1e-11;
const double PI = acos ( -1.0 );
const double E = 2.718281828;
typedef long long ll;

const int INF = 1000010;

using namespace std;

int cnt[250], sum[250];///保存在一行中所有符合情况的值
int mp[110];//用来表示每行的情况,1代表不能安排士兵,0可以
int len, n, m;
int dp[110][250][250];

bool ok ( int x )
{
    if ( x & ( x << 2 ) ) return false;///同一行距离为2的有没有冲突
    return true;
}

int getsum ( int x )///没有冲突的时候计算1的个数
{
    int ans = 0;
    while ( x > 0 )
    {
        if ( x & 1 )//最后一位是1
            ans++;
        x >>= 1;///右移一位
    }
    return ans;
}

void finds()///算出所有符合情况的值
{
    len = 0;
    memset ( cnt, 0, sizeof cnt );
    for ( int i = 0; i < ( 1 << m ); i++ )
    {
        if ( ok ( i ) )
        {
            cnt[len] = i;
            sum[len++] = getsum ( i );
        }
    }
    //cout << len << endl;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while ( cin >> n >> m )
    {
        //m = 10;
        finds();
        int c;
        memset ( mp, 0, sizeof ( mp ) );
        for ( int i = 0; i < n; i++ )
        {
            for ( int j = 0; j < m; j++ )
            {
                scanf ( "%d", &c );///为了方便计算,吧、把1存为0,把0存为1
                if ( !c )
                    mp[i] |= ( 1 << j );
            }
        }
        memset ( dp, -1, sizeof ( dp ) );
        for ( int i = 0; i < len; i++ )///先处理第一行
        {
            if ( ! ( cnt[i]&mp[0] ) )
                dp[0][i][0] = sum[i];
        }
        for ( int i = 1; i < n; i++ )
        {
            for ( int j = 0; j < len; j++ )
            {
                if ( cnt[j]&mp[i] )///与mp[i]有冲突
                    continue;
                for ( int k = 0; k < len; k++ )///i-1行的情况
                {
                    if ( ( ( cnt[k] << 1 ) &cnt[j] ) || ( ( cnt[k] >> 1 ) &cnt[j] ) ) continue;///左右一个单位的对角上有人的情况
                    for ( int l = 0; l < len; l++ )///i-2行
                    {
                        if ( cnt[j]&cnt[l] )///第i行与第2行有冲突
                            continue;
                        if ( ( ( cnt[l] << 1 ) &cnt[k] ) || ( ( cnt[l] >> 1 ) &cnt[k] ) ) continue;///i-1行与i-2行
                        if ( dp[i - 1][k][l] == -1 )
                            continue;
                        if ( dp[i - 1][k][l] + sum[j] > dp[i][j][k] )
                            dp[i][j][k] = dp[i - 1][k][l] + sum[j];
                    }
                }
            }
        }
        int ans = -1;
        for ( int i = 0; i < len; i++ )
            for ( int j = 0; j < len; j++ )
                if ( ans < dp[n - 1][i][j] )
                    ans = dp[n - 1][i][j];
        cout << ans << endl;
    }
    return 0;
}
时间: 2024-10-10 13:02:58

HDU 4539 郑厂长系列故事――排兵布阵(状态压缩)的相关文章

HDU 4539 郑厂长系列故事——排兵布阵 (状态压缩DP)

中文题,题意不再累赘. 思路:对于第 i 行的放士兵,影响它的只有第 i-1 行和 i-2 行,所以暴力枚举符合这三行的状态 state[i],state[j],state[k].  接下来就是二进制的巧妙应用了. 具体题解看代码注释!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath&

HDU ACM 4539 郑厂长系列故事——排兵布阵-&gt;状态压缩DP

分析:dp[i][j][k]表示第i行状态为j,i-1行状态为k时的客房士兵的最大值. 曼哈顿距离是指:|x1-x2|+|y1-y2|. 当前行不仅与前一行有关,还和前两行有关,所以开数组的时候还要记录前两行的状态,所以开设三维数组. 每行可压缩为二进制集合,状态dp[i][j][k]为第i行为集合j,第i-1行为集合k,则状态方程dp[i][j][k] = max{dp[i-1][k][r]+cnt[j]  | 状态i,j,k要能够共存}(cnt[j]为j在二进制下的1的个数,即士兵数).第一

HDU 4539郑厂长系列故事――排兵布阵(状压DP)

HDU 4539  郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 1 //#pragma comment(linker,"/STACK:102400000,102400000") 2 #include <map> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #i

HDU 4539 郑厂长系列故事——排兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1708    Accepted Submission(s): 620 Problem Description 郑厂长不是正厂长 也不是副厂长 他根本就不是厂长 事实上

HDU 4539 郑厂长系列故事――排兵布阵

/* 曼哈顿距离的定义是:两个点的坐标为(x1,y1),(x2,y2),两点的曼哈顿距离为|x1-x2|+|y1-y2| 题意:题上要求是两个士兵的距离不能是曼哈顿距离为2,意思就是这个点在同一行同一列不能相间,这个点的左上,左下,右上,右下角不能有 士兵. 思路:dp+状态压缩dp[i][j][k]定义的状态为i是当前行,j为当前行的状态,k为上一行的状态类似炮兵阵地 */ #include<stdio.h> #include<string.h> #define Max(a,b)

HDU 4539 郑厂长系列故事——排兵布阵 &lt;&lt;状压dp

思路 被这道题折磨死了,只是发上来纪念一下,思路同方格取数(1),我已经疯了! 代码 1 #include<bits/stdc++.h> 2 using namespace std; 3 int maze[110][15]; 4 int n,m; 5 vector<int> all[110]; 6 int dp[110][200][200]; 7 int num[1<<10]; 8 bool check(int r,int state) 9 { 10 for(int i

[状压dp]HDOJ4539 郑厂长系列故事——排兵布阵

中文题,题意不再赘述 对于“?”这一格,它所能攻击到的(曼哈顿距离为2的) 前方的 即“√”的四个位置 那么与此格有关的即它前方两行(即状压这两行) 首先预处理每行能满足的: i 和(i<<2)不能同时放 然后分别枚举前一行和再前一行的所有状态(每一行的状态至多只有2^10=1024个) 判断能否共存 注意mp==1处才能放,mp==0处不能放 HDOJ 4539

HDU - 4529 郑厂长系列故事――N骑士问题 (状态压缩DP)

Description 郑厂长不是正厂长 也不是副厂长 他根本就不是厂长 还是那个腾讯公司的码农 一个业余时间喜欢下棋的码农 最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了.兴奋之余,坐在棋盘前的他又开始无聊了.无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子.因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击. 现在郑厂长想

[AC自动机+状压dp] hdu 4534 郑厂长系列故事——新闻净化

题意:中文的题目,意思就是说有很多串,每个串都有权值,权值为999的串必须出现,-999的串必须不出现.权值在-999~999之间. 然后必须出现的串不超过8个.然后给一个全为小写目标串,问最少需要删除多少个字母才能够保证必须出现的串都出现,次数一样保证权值最大.输出次数和权值. 然后根据样例,那些必须出现的串,其实权值是0. 思路: 很明显一开始建自动机构成trie图,但是需要注意的就是mark和sum的更新.个人是把所有中间的节点的sum全部赋值成了-inf. 接着只有8个必须出现的串,所以