zoukankan      html  css  js  c++  java
  • LA 4794 状态DP+子集枚举

    状态压缩DP,把切割出的面积做状态压缩,统计出某状态下面积和。

    设f(x,y,S)为在状态为S下在矩形x,y是否存在可能划分出S包含的面积。若S0是S的子集,对矩形x,y横切中竖切,对竖切若f(x,k,S0)且f(x,y-k,S^S0)为真,则为真,对横切同样。

    然后枚举S的子集即可。可以用记忆化搜索。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    int dp[105][(1<<15)+5];
    bool vis[105][(1<<15)+5];
    int area[105];
    int se[1<<15];
    
    int counts(int s){
    	int res=0;
    	while(s){
    		if(s&1) res++;
    		s>>=1;
    	}
    	return res;
    }
    
    int dfs(int x,int st){
    	if(vis[x][st]) return dp[x][st];
    	int y=se[st]/x;
    	vis[x][st]=true;
    	if(counts(st)==1) return dp[x][st]=1;
    	for(int s0=(st-1)&st;s0;s0=(s0-1)&st){
    		if(se[s0]%x==0&&dfs(min(x,se[s0]/x),s0)&&dfs(min(x,se[s0^st]/x),s0^st))
    		 return dp[x][st]=1;
    	 	if(se[s0]%y==0&&dfs(min(y,se[s0]/y),s0)&&dfs(min(y,se[s0^st]/y),s0^st))
    	 	 return dp[x][st]=1;
    	}
    	return dp[x][st]=0;
    }
    
    int main(){
    	int n,x,y,sum,icase=0;
    	while(scanf("%d",&n),n){
    		scanf("%d%d",&x,&y);
    		sum=0;
    		for(int i=0;i<n;i++){
    			scanf("%d",&area[i]);
    			sum+=area[i];
    		}
    		for(int i=0;i<(1<<n);i++){
    			se[i]=0;
    			for(int j=0;j<n;j++){
    				if((1<<j)&i) se[i]+=area[j];
    			}
    		}
    		memset(vis,false,sizeof(vis));
    		printf("Case %d: ",++icase);
    		if(sum!=x*y||sum%x!=0||sum%y!=0){
    			puts("No");
    		}
    		else{
    			dfs(min(x,y),(1<<n)-1);
    			if(dp[min(x,y)][(1<<n)-1]) puts("Yes");
    			else puts("No");
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    大话测试数据(一)
    两个小案例
    关于那些难改的bug
    关于测试人员的职业发展
    python中的模块
    python为什么会有@classmethod?
    Javascript oop深入学习笔记(三)--javascript中类的实现
    NODE编程(一)--Node功能的组织和重用
    javascript oop深入学习笔记(二)--javascript的函数
    javascript oop深入学习笔记(一)
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4546111.html
Copyright © 2011-2022 走看看