cf298F:状压dp+剪枝
div2的F题,只想到了一个复杂度略高的dp,T了几次,后来加了剪枝减掉一些无用的状态终于过了。。
题意:
一个n*m的矩阵 (n<=5,m<=20),对格子进行黑白染色,已经给出了每行每列黑色联通块的个数,要求输出一组答案,满足有解。
思路:
首先发现n只有5,考虑按列处理,每列总共有2^5=32种状态;又发现对于给出的联通块个数,最坏情况是当联通块个数等于1或者2的时候有15种情况
比直接二进制处理快了一倍。所以我们可以预先处理出联通块个数为0~3时对于的二进制状态;
找到了列的基本状态,现在来考虑转移:
首先在转移时应该满足每行的黑色联通块个数,所以每行当前的联通块个数是需要保存的,由于m<=20所以每行最多有0~10这11种情况,考虑到5行就总共有11^5种状态
所以总共的状态数即为 20*15*11^5=48315300 由于cf的机器很强大这个状态数基本算是可以接受了
转移时处理如下:对于每一行如果上一列为0且当前列为1,则联通块数目+1,其他情况联通块数目不变。
这样我们就可以解决整个dp的过程了,由于题目要求输出染色方案,我们就需要记录每一个状态的前驱,最后通过前驱获得答案
但是直接交上去还是会T的,这里有两个剪枝可以使用
1.在转移过程中如果当前行的联通块个数已经大于题目给的个数,直接把这个状态减掉
2.在转移过程中如果当前行的联通块个数在剩下的列里怎么取(最好情况为一黑一白这样染)都不可能达到题目给的个数,把这个状态减掉
最后终于ac了!
代码:
#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
#include<vector>
using namespace std;
#define MAXN 10000
bool dp[][][];
int pret[];
int x[];
int y[];
int p[];
int ans[];
int v[][];
int nn[];
int n,m;
int fun(int s)
{
int res=;
int pre=;
for(int i=; i<n; i++)
{
if((s&(<<i))&&pre==)
{
res++;
}
pre=(bool)(s&(<<i));
}
return res;
}
inline int get(int s,int i)
{
return (s%p[i+])/p[i];
}
int fuck(int s,int pre,int now,int pos)
{
int res=;
for(int i=; i<n; i++)
{
int tmp=(get(s,i)+((!(pre&(<<i)))&&(now&(<<i))));
if(tmp>x[i])
return -;
if(tmp+(m-pos)/<x[i])
return -;
res+=tmp*p[i];
}
return res;
}
inline int make(int i,int j,int s)
{
return s+j*+i**;
} inline int getj(int t)
{
return (t%(*))/;
} char s[][];
int main()
{
cin>>n>>m;
p[]=;
for(int i=; i<=; i++)
{
p[i]=p[i-]*;
}
for(int i=; i<(<<n); i++)
{
int tmp=fun(i);
v[tmp][nn[tmp]++]=i;
}
for(int i=; i<n; i++)
{
cin>>x[i];
}
for(int i=; i<m; i++)
{
cin>>y[i];
}
for(int i=; i<nn[y[]]; i++)
{
dp[][i][fuck(,,v[y[]][i],)]=;
}
int now,pre,st;
for(int i=; i<m; i++)
{
for(int j=; j<nn[y[i-]]; j++)
{
for(int s=; s<; s++)
{
if(dp[i-][j][s])
{
for(int k=; k<nn[y[i]]; k++)
{
st=fuck(s,v[y[i-]][j],v[y[i]][k],i);
if(st<)
continue;
dp[i][k][st]=;
pret[make(i,k,st)]=make(i-,j,s);
}
}
}
}
}
now=;
for(int i=;i<n;i++)
{
now+=x[i]*p[i];
}
int j=-;
for(int i=;i<nn[y[m-]];i++)
{
if(dp[m-][i][now])
{
j=i;
break;
}
} now=make(m-,j,now);
for(int i=m-;i>=;i--)
{
ans[i]=v[y[i]][getj(now)];
now=pret[now];
}
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
s[i][j]=((ans[j])&(<<i))?'*':'.';
}
}
for(int i=;i<n;i++)
{
puts(s[i]);
}
return ;
}
cf298F:状压dp+剪枝的更多相关文章
- Atcoder Typical DP Contest S - マス目(状压 dp+剪枝)
洛谷题面传送门 介绍一个不太主流的.非常暴力的做法( 首先注意到 \(n\) 非常小,\(m\) 比较大,因此显然以列为阶段,对行的状态进行状压.因此我们可以非常自然地想到一个非常 trivial 的 ...
- hdu 4739 状压DP
这里有状态压缩DP的好博文 题目:题目比较神,自己看题目吧 分析: 大概有两种思路: 1.dfs,判断正方形的话可以通过枚举对角线,大概每次减少4个三角形,加上一些小剪枝的话可以过. 2.状压DP,先 ...
- 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)
洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...
- NOIp2017D2T2(luogu3959) 宝藏 (状压dp)
时隔多年终于把这道题锅过了 数据范围显然用搜索剪枝状压dp. 可以记还有哪些点没到(或者已到了哪些点).我们最深已到的是哪些点.这些点的深度是多少,然后一层一层地往下推. 但其实是没必要记最深的那一层 ...
- dp,状压dp等 一些总结
也就作业几题而已,分析一下提醒 最重要的就是,记住,没用的状态无论怎么转移最后都会是没用的状态,所以每次转移以后的有值的状态都是有用的状态. 几种思考方向: 第一种:枚举当前的状态,转移成另外一个状态 ...
- NOIP2016愤怒的小鸟 [状压dp]
愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...
- 【NOIP2017】宝藏 题解(状压DP)
题目描述 参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 nnn 个深埋在地下的宝藏屋, 也给出了这 nnn 个宝藏屋之间可供开发的m mm 条道路和它们的长度. 小明决心亲自前往挖掘所有宝藏屋中 ...
- T2988 删除数字【状压Dp+前缀和优化】
Online Judge:从Topcoder搬过来,具体哪一题不清楚 Label:状压Dp+前缀和优化 题目描述 给定两个数A和N,形成一个长度为N+1的序列,(A,A+1,A+2,...,A+N-1 ...
- 「状压DP」「暴力搜索」排列perm
「状压DP」「暴力搜索」排列 题目描述: 题目描述 给一个数字串 s 和正整数 d, 统计 sss 有多少种不同的排列能被 d 整除(可以有前导 0).例如 123434 有 90 种排列能被 2 整 ...
随机推荐
- JStorm 是一个分布式实时计算引擎
alibaba/jstorm JStorm 是一个分布式实时计算引擎. JStorm 是一个类似Hadoop MapReduce的系统, 用户按照指定的接口实现一个任务,然后将这个任务递交给JStor ...
- PowerDesigner 生成带凝视SQL 各个版本号通用10(12、15)
做数据库是设计时最苦恼的事就是用PowerDesigner工具设计完数据库运行SQL文件后没有凝视.那么怎么才干让PowerDesigner设计完有凝视呢,下边教你一个笨的方法,方法尽管笨,可是能实现 ...
- JQuery window、document、 body (转)
转自:http://www.cnblogs.com/luhe/archive/2012/11/08/2760619.html 我电脑屏幕分辨率:1440 * 900 最大化浏览器,刷新浏览器 al ...
- Eclipse、MyEclipse使用git插件(egit)
在开发Java.JavaEE等相关程序时,我们会用到Eclipse或者MyEclipse,同时使用到git作为版本控制软件,所以我们需要在这些IDE上集成git插件,而egit正是Eclipse基金会 ...
- Python第一课
一.模块的常用方法 __name__ #主模块name值main __file__ #文件所在的路径+文件名 __doc__ #文件级别的注释 二.函数 参数 参数默认值 可变参数 ...
- Linux shell入门基础(二)
二.shell对文本的操作 01.查看文本的命令 #cat /etc/passwd(并非对文本文件操作) #tail -5 /etc/passwd(查看末尾5行) #tail -f /var/log/ ...
- 快速使用shortcut,适配各种ROM
地址(徐医生的GitHub):https://github.com/xuyisheng/ShortcutHelper 常用API /** * 添加快捷方式 * * ...
- JPush 极光推送 消息推送 实例
简介 官网:https://www.jpush.cn/ 极光推送(JPush)是一个端到端的推送服务,使得服务器端消息能够及时地推送到终端用户手机上,让开发者积极地保持与用户的连接,从而提高用户活跃度 ...
- nyoj 17
// nyoj 17 代码如上,用的是dp,总的来说就是对一个字符串 从末尾开始比较,设定一个数组,存放每个单调字串的最大长度,最后比较... //要注意的就是里面if语句对于每次字符比 ...
- id名和class名有什么区别
从概念上来说: id是先找到结构/内容,再给它定义样式: class是先定义好一种样式,再套给多个结构/内容. 从样式效果上来说: id的优先级要比class高出一个层次 html中不管有几个i ...