zoukankan      html  css  js  c++  java
  • [POJ1185]炮兵阵地

    [POJ1185]炮兵阵地

    试题描述

    司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 


    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

    输入

    第一行包含两个由空格分割开的正整数,分别表示N和M; 
    接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

    输出

    仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

    输入示例

    5 4
    PHPP
    PPHH
    PPPP
    PHPP
    PHHP

    输出示例

    6

    数据规模及约定

    见“输入

    题解

    观察到 m 很小,所以很自然想到状态压缩。这里我们还需要一个工作,不妨用程序统计一下 m = 10 时一行中可行的摆放方案有多少种,就是 210 枚举一下,然后排掉那些挨得太近的情况,发现只有 60 种。于是就可以设 f(i, j, k) 表示考虑前 i 行,最后两行放置炮兵的集合分别为 j 和 k,我们把那 60 种方案离散一下就可以 dp 了。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    int read() {
        int x = 0, f = 1; char c = getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
        return x * f;
    }
    
    #define maxn 110
    #define maxm 15
    int n, m, St[maxn], f[maxn][maxn][maxn];
    char Map[maxn][maxm];
    
    void up(int& a, int b) {
    	a = max(a, b);
    	return ;
    }
    
    void print(int x) {
    	int num[15], cnt = 0;
    	memset(num, 0, sizeof(num));
    	while(x) num[++cnt] = x & 1, x >>= 1;
    	for(int i = 1; i <= 4; i++) putchar(num[i] + '0');
    	putchar(' ');
    	return ;
    }
    
    int main() {
    	n = read(); m = read();
    	for(int i = 1; i <= n; i++) scanf("%s", Map[i] + 1);
    	
    	int all = (1 << m) - 1, cnt = 0;
    	for(int i = 0; i <= all; i++) {
    		bool ok = 1;
    		for(int j = 0; j < m; j++)
    			if((i >> j & 1) && ((i >> j + 1 & 1) || (i >> j + 2 & 1))) {
    				ok = 0; break;
    			}
    		if(ok) St[++cnt] = i;
    	}
    //	for(int i = 1; i <= cnt; i++) print(St[i]); putchar('
    ');
    	memset(f, -1, sizeof(f));
    	f[0][1][1] = 0;
    	for(int i = 0; i < n; i++)
    		for(int j = 1; j <= cnt; j++)
    			for(int k = 1; k <= cnt; k++) if(f[i][j][k] >= 0) {
    				int S1 = St[j], S2 = St[k];
    				for(int l = 1; l <= cnt; l++) if(!(S1 & St[l]) && !(S2 & St[l])) {
    					int S = St[l];
    					bool ok = 1; int cal = 0;
    					for(int x = 0; x < m; x++) {
    						if((S >> x & 1) && Map[i+1][x+1] == 'H') {
    							ok = 0; break;
    						}
    						cal += (S >> x & 1);
    					}
    					if(!ok) continue;
    					up(f[i+1][k][l], f[i][j][k] + cal);
    //					printf("to: %d ", i + 1); print(S2); print(S);
    //					printf("%d %d %d
    ", f[i+1][k][l], f[i][j][k], cal);
    				}
    //				printf("%d ", i); print(S1); print(S2); printf("%d
    ", f[i][j][k]);
    			}
    	
    	int ans = -1;
    	for(int i = 1; i <= cnt; i++)
    		for(int j = 1; j <= cnt; j++) up(ans, f[n][i][j]);
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    

    终于在 POJ 上看到一道中文题。。。

  • 相关阅读:
    OpenCR 固件修复
    E-PUCK2机器人-固件更新
    E-puck2机器人系列教程-2.软件的安装与使用
    E-PUCK2机器人-硬件
    E-puck2机器人系列教程-固件修复升级
    GridView
    TimePicker 和TimePickerDiag
    android中实现简单的播放
    ListView的使用
    android的activity的跳转
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6107564.html
Copyright © 2011-2022 走看看