zoukankan      html  css  js  c++  java
  • 【JZOJ2679】跨时代【dfs】【状压】【背包】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/2679
    给出nn根线段的长度,选择其中一些线段组成一个长方形似的这个长方形的面积最大。


    思路:

    如果我们选择其中一些线段,设这些线段长度和为kk,若可以从这些已选线段中再找出一些线段使得这些线段长度为k2frac{k}{2},那么这些长度和为kk的线段就可以分成两组长度和为k2frac{k}{2}的线段,而这两组线段就可以作为矩形的一组对边。
    考虑O(3n)O(3^n)暴力枚举每一条边选或不选,那么最终会得到选择为长、宽的两组集合。如果这两组集合的长度和都可以作为对边,那么这就形成了一个矩形。
    所以预处理出每一个集合是否可以分为两个小集合。设ss为状压后的集合,f[s]f[s]为集合中的元素之和,那么我们就要在这些元素中选择其中一部分使得他们的和为f[s]2frac{f[s]}{2}
    这就是一个基础的01背包问题,套进去就可以了。
    时间复杂度O(3n)O(3^n)


    代码:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int N=20,MAXN=100010,M=250;
    int n,ans,maxn,sum,a[N],f[MAXN];
    bool g[M],p[MAXN];
    
    void dfs(int x,int s1,int s2,int S1,int S2)
    {
    	if (x>n)
    	{
    		if (p[S1] && p[S2] && s1/2*s2/2>ans) ans=s1/2*s2/2;
    		return;
    	}
    	dfs(x+1,s1,s2,S1,S2);
    	dfs(x+1,s1+a[x],s2,S1|(1<<x-1),S2);
    	dfs(x+1,s1,s2+a[x],S1,S2|(1<<x-1));
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	maxn=(1<<n)-1;
    	for (int i=1;i<=maxn;i++)
    	{
    		for (int j=1;j<=n;j++)
    			if (i&(1<<j-1)) f[i]+=a[j];
    		if (f[i]&1) continue;
    		memset(g,0,sizeof(g));
    		g[0]=1;
    		for (int k=1;k<=n;k++)
    			for (int j=f[i]/2;j>=a[k];j--)
    				if ((i&(1<<k-1))) g[j]|=g[j-a[k]];
    		if (g[f[i]/2]) p[i]=1;
    	}
    	dfs(1,0,0,0,0);
    	if (ans) printf("%d",ans);
    		else printf("No Solution");
    	return 0;
    }
    
  • 相关阅读:
    MFC Bitmap::FromBITMAPINFO返回空问题
    String成员函数
    用xshell连接l自己的inux
    回调函数
    文件操作相关函数(POSIX 标准 open,read,write,lseek,close)
    Linux_GDB调试学习笔记
    程序中的一些限制(基于Linux系统C语言)
    第10课:[实战] Redis 网络通信模块源码分析(3)
    第09课:【实战】Redis网络通信模块源码分析(2)
    简单模拟多段线绘制Pline命令过程的撤销功能
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998118.html
Copyright © 2011-2022 走看看