zoukankan      html  css  js  c++  java
  • POJ1185 炮兵阵地 和 POJ2411 Mondriaan's Dream

    炮兵阵地

    Language:
    炮兵阵地
    Time Limit: 2000MSMemory Limit: 65536K
    Total Submissions: 34008Accepted: 13083

    Description

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

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

    Input

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

    Output

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

    Sample Input

    5 4
    PHPP
    PPHH
    PPPP
    PHPP
    PHHP

    Sample Output

    6

    Source

    分析

    由于会影响两行,所以需要在行数以外增加两维状态。

    预处理出单行的合法状态,大概在60左右,然后枚举转移即可。

    时间复杂度(o(n 60^3)),由于地形的因数,状态量又会减少,上界很松。

    #include<iostream>
    #include<cstring>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using std::max;
    
    int dp[101][77][77];
    int sg[101];
    int n,m,idx,s[77],cnt0[77];
    int get_one(int x){
    	int cnt=0;
    	while(x) x&=x-1,++cnt;
    	return cnt;
    }
    bool ok(int x){
    	return x&x<<1||x&x<<2?0:1;
    }
    void init(){
    	for(int i=0;i<1<<m;++i)if(ok(i)){
    		s[idx]=i,cnt0[idx++]=get_one(i);
    	}
    }
    bool valid(int i,int x){
    	return sg[i]&x?0:1;
    }
    int solve(){
    	int ans=0;
    	memset(dp,-1,sizeof dp);
    	dp[0][0][0]=0;
    	for(int i=0;i<idx;++i)if(valid(1,s[i])){
    		dp[1][i][0]=cnt0[i];
    		ans=max(ans,dp[1][i][0]);
    	}
    	for(int i=2;i<=n;++i)
    		for(int j=0;j<idx;++j)if(valid(i,s[j]))
    			for(int k=0;k<idx;++k)if(valid(i-1,s[k])&&(s[j]&s[k])==0){
    				int last=0;
    				for(int l=0;l<idx;++l)if(dp[i-1][k][l]!=-1&&(s[l]&s[j])==0)
    					last=max(last,dp[i-1][k][l]);
    				dp[i][j][k]=max(dp[i][j][k],last+cnt0[j]);
    				if(i==n) ans=max(ans,dp[i][j][k]);
    			}
    	return ans;
    }
    int main(){
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	read(n),read(m);
    	for(int i=1;i<=n;++i){
    		static char s[11];
    		scanf("%s",s);
    		for(int j=0;j<m;++j)
    			if(s[j]=='H') sg[i]|=1<<j;
    	}
    	init();
    	printf("%d
    ",solve());
    	return 0;
    }
    

    Mondriaan's Dream

    Language:
    Mondriaan's Dream
    Time Limit: 3000MSMemory Limit: 65536K
    Total Submissions: 21909Accepted: 12282

    Description

    Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways.

    Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!

    Input

    The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.

    Output

    For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.

    Sample Input

    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    2 11
    4 11
    0 0
    

    Sample Output

    1
    0
    1
    2
    3
    5
    144
    51205
    

    Source

    分析

    网上一些题解都是什么鬼,轮廓线、插头DP都冒出来了。

    (F[i,j])表示前(i)行,第(i)行的放置状态为(j)的方案数,把特殊的(1 imes 2)矩形的上半部分的状态定为1。

    这样(j)能转移到(k),当且仅当

    1. (j&k=0),显然的。
    2. (j|k)的每一段连续的0的数量必须有偶数个,这体现了(2 imes 1)矩形的要求。

    预处理出那些状态转移合法,大力转移即可。

    时间复杂度(O(n 2^{2m}))

    #include<iostream>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    
    int n,m;
    ll f[12][1<<11];
    bool in_s[1<<11];
    int main(){
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	while(read(n)|read(m)){
    		for(int i=0;i<1<<m;++i){
    			bool cnt=0,has_odd=0;
    			for(int j=0;j<m;++j){
    				if(i>>j&1) has_odd|=cnt,cnt=0;
    				else cnt^=1;
    			}
    			in_s[i]=has_odd|cnt?0:1;
    		}
    		f[0][0]=1;
    		for(int i=1;i<=n;++i)
    			for(int j=0;j<1<<m;++j){
    				f[i][j]=0;
    				for(int k=0;k<1<<m;++k)
    					if((j&k)==0&&in_s[j|k])
    						f[i][j]+=f[i-1][k];
    			}
    		printf("%lld
    ",f[n][0]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux命令大全
    【转载】nginx的五种负载算法
    nginx服务器安装及配置文件详解
    查看linux系统核数
    利用nginx实现分流
    ntohs, ntohl, htons,htonl的比较和详解
    Nginx反向代理之HTTP 请求头中的 X-Forwarded-For
    javascript中 for in 、for 、forEach 、for of 、Object.keys().
    vue里面路由传参的三种方式
    vue中ref在input中详解
  • 原文地址:https://www.cnblogs.com/autoint/p/10667861.html
Copyright © 2011-2022 走看看