zoukankan      html  css  js  c++  java
  • 西电oj 1038 状压dp

    西电oj 1038  状压dp

    1038: 裁玻璃

    时间限制: 1 Sec  内存限制: 128 MB
    提交: 33  解决: 4
    [提交][状态][讨论版]

    题目描述

    张老板的玻璃店开张了,生意火爆。今天,隔壁玻璃店的刘老板拿来一块玻璃,意在刁难张老板。刘老板说:“我这块玻璃是由N(行)*M(列)小正方形玻璃拼成的,但是其中有一些玻璃坏了,我希望你现在把它裁成尽量多的2*2的小玻璃,而且这些小玻璃都不能有坏的地方。如果你裁出来的块数不是最多的,我就把你赶出建材市场。”
    现在,张老板来拜托你帮他解决这个问题,聪明的你可以告诉张老板,最多能裁出多少块2*2的小玻璃吗?

    输入

    有多组输入数据,第一行为一个数字T,代表有T组输入数据 (0<T<=30)。
    接下来为T组数据,每组数据的第一行为两个正整数N和M(1<=N<=10,1<=M<=10),表示玻璃的大小,接下来的N行、每行M个数字(0或1)表示玻璃中每个位置的状态,0表示这个位置是坏的,1表示这个位置是好的。

    输出

    一共T行。
    对于每组数据,输出一个整数,表示最多的2*2小玻璃块数。

    样例输入

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

    样例输出

    1
    3
    思路:和poj1185一样,状压dp,dp(i,j)=max(dp(i,j),dp(i-1,k)+sum[j])(状态j,k存在合法且不冲突)
        dp表示第i行的状态为j时的玻璃数,按行进行递推,sum[j]表示状态为j时这一行的玻璃数。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=1100;
    const int INF=(1<<29);
    
    int N,M;
    int Map[maxn];
    int dp[maxn][maxn];
    int state[maxn],sum[maxn],cnt;
    
    void InitState()
    {
        memset(state,0,sizeof(state));
        cnt=0;
        for(int i=0;i<(1<<(M-1));i++){
            if((i&(i<<1))) continue;
            state[cnt++]=i;
        }
    }
    
    void InitSum()
    {
        memset(sum,0,sizeof(sum));
        for(int i=0;i<cnt;i++){
            for(int j=0;j<M-1;j++){
                if(state[i]&(1<<j)) sum[i]++;
            }
        }
    }
    
    bool jud_map(int i,int row)
    {
        int s=state[i];
        bool flag=1;
        for(int j=0;j<M-1;j++){
            if(s&(1<<j)){
                if(Map[row]&(1<<j)&&(Map[row]&(1<<(j+1)))&&(Map[row+1]&(1<<j))&&(Map[row+1]&(1<<(j+1)))) continue;
                else{
                    flag=0;break;
                }
            }
        }
        return flag;
    }
    
    bool jud(int a,int b)
    {
        int s=state[a],t=state[b];
        if((s&t)||(s&(t<<1))||((s<<1)&t)) return 0;
        return 1;
    }
    
    int main()
    {
        int T;cin>>T;
        while(T--){
            cin>>N>>M;
            memset(Map,0,sizeof(Map));
            for(int i=1;i<=N;i++){
                int t;
                for(int j=0;j<M;j++){
                    scanf("%d",&t);
                    if(t) Map[i]|=(1<<j);
                }
            }
            InitState();
            InitSum();
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=N-1;i++){
                for(int j=0;j<cnt;j++){
                    if(!jud_map(j,i)) continue;
                    if(i==1){
                        dp[i][j]=max(dp[i][j],sum[j]);
                        continue;
                    }
                    else{
                        for(int k=0;k<cnt;k++){
                            if((!jud_map(k,i-1))||(!jud(j,k))) continue;
                            dp[i][j]=max(dp[i][j],dp[i-1][k]+sum[j]);
                        }
                    }
                }
            }
            int ans=0;
            for(int i=0;i<cnt;i++){
                if(dp[N-1][i]>ans) ans=dp[N-1][i];
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code


    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    AJAX补充
    JQuery知识补充2
    JQuery知识补充1
    LiveBOS使用指南
    HTML5(1)
    .net 后台导出excel ,word
    Eval绑定方法:多条件绑定:
    repeater 的用法
    两个页面地址栏传值
    js取后台的值
  • 原文地址:https://www.cnblogs.com/--560/p/4506685.html
Copyright © 2011-2022 走看看