BZOJ2595:[Wc2008]游览计划——题解(插头dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=2595
Description
Input
第一行有两个整数,N和 M,描述方块的数目。
接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点;
否则表示控制该方块至少需要的志愿者数目。 相邻的整数用 (若干个) 空格隔开,
行首行末也可能有多余的空格。Output
由 N + 1行组成。第一行为一个整数,表示你所给出的方案
中安排的志愿者总数目。
接下来 N行,每行M 个字符,描述方案中相应方块的情况:
z ‘_’(下划线)表示该方块没有安排志愿者;
z ‘o’(小写英文字母o)表示该方块安排了志愿者;
z ‘x’(小写英文字母x)表示该方块是一个景点;
注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不
一致(任何一行中,多余的空格都不允许出现) ,都可能导致该测试点不得分。Sample Input
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0Sample Output
6
xoox
___o
___o
xoox
参(抄)考(了):http://www.sigongzi.org/index.php/archives/jiyuliantongxingdezhuangtaiyasuodongtaiguihua.html
……原本也不想抄的啊,不然括号表达法还得学独立插头……
打眼一看就是一个插头dp,于是我们选用最小表示法求解。插头dp详见这里。
但是我们最开始学的插头dp只能解决哈密顿回路啊根本没有这道题这么复杂这可怎么办?
别慌,我们慢慢理:
1.显然景点是必须要取的(插头不能为“0”)。
2.显然路径必须是互相联通的线段。
对于1,我们强制不让这个格子不放插头即可。
对于2,我们考虑如果我们当前格子的上插头在轮廓线再没有与之相连通的插头,且同时我们已经扫完了所有景点,此时我们不选当前格子的话我们就将分开成两条路径了,所以必须要取;但是如果是左插头的话如果不取的话是可能符合2的。
然后正常插头dp即可。
(写这道题写了一天的我……)
(如果你插头dpA了这道题可以试一下这个数据):
4 3
0 1 1
10 10 1
10 10 0
10 10 1
ans:
3
xoo
__o
__x
___
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=;
const int mod=;
const int N=;
const int M=;
struct node{//哈希表
int nxt;
int state,ans,pos,pre;//状态,答案,编号,前一个状态
bool choose;//是否选择该方块
}edge[M];
int head[mod+],cnt;
int lcnt,rcnt;
void insert(int now,int num,int ppos,int last,bool flag){
int u=now%mod;
for(int i=head[u];i;i=edge[i].nxt){
if(edge[i].state==now){
if(num<edge[i].ans){
edge[i].ans=num;
edge[i].pos=ppos;
edge[i].pre=last;
edge[i].choose=flag;
}
return;
}
}
edge[++cnt].nxt=head[u];
head[u]=cnt;
edge[cnt].state=now;
edge[cnt].ans=num;
edge[cnt].pos=ppos;
edge[cnt].pre=last;
edge[cnt].choose=flag;
return;
}
bool g[N][N];
int w[N],cntt;
int n,m,lastedge,e1,e2;
int mp[N][N];
int mapp[N];
inline void decode(int now){
for(int i=m;i>=;i--){
w[i]=now&;
now>>=;
}
return;
}
inline int encode(){
int x=,tot=;
memset(mapp,-,sizeof(mapp));
mapp[]=;
for(int i=;i<=m;i++){
if(mapp[w[i]]==-)mapp[w[i]]=++tot;
w[i]=mapp[w[i]];
x=x<<|w[i];
}
return x;
}
inline void init(){
memset(head,,sizeof(head));
lcnt=rcnt+;rcnt=cnt;
return;
}
inline void getans(){
for(int k=lcnt;k<=rcnt;k++){
int now=edge[k].state;
int num=edge[k].ans;
decode(now);
bool flag=;
for(int l=;l<=m&&flag;l++){
if(w[l]>)flag=;
}
if(num<cntt&&flag){
cntt=num;
lastedge=k;
}
}
return;
}
void plugdp(){
insert(,,,,);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
init();
if(i>e1||(i==e1&&j>e2))getans();//当前状态可能构成一种方案
for(int k=lcnt;k<=rcnt;k++){
int now=edge[k].state;
int num=edge[k].ans;
decode(now);
int is_right=w[j-];//这个格子左面格子的右插头
int is_down=w[j];//这个格子上面格子的下插头
bool flag=;//判断是否可以放插头,1可以不放
if(!mp[i][j])flag=;//景点必须放
else if(!is_down)flag=;//下插头不需要再匹配,故可以不放。
else{
flag=;
for(int l=;l<=m&&!flag;l++){
if(l!=j&&w[l]==is_down)flag=;
//上插头已经与轮廓线的一端匹配,可以在那一端延伸。
}
//没有匹配的插头,必须要接上
}
if(flag){//不放插头
w[j]=;//下插头没有用了
insert(encode(),num,(i-)*m+j,k,);
w[j]=is_down;
}
//放插头
if(!is_right&&!is_down)w[j]=;//一个新插头
else if(!is_down&&is_right)w[j]=is_right;//右插头延续过来
else if(is_right!=is_down&&is_right&&is_down){
for(int l=;l<=j;l++){//不太好说,但画个图应该就理解了
if(w[l]==is_right)w[l]=is_down;
}
}
//如果下插头和右插头匹配那么就把它们连起来
insert(encode(),num+mp[i][j],(i-)*m+j,k,);
}
}
}
init();
getans();
return;
}
void getans(int k){
if(!k)return;
int r=edge[k].pos;
int l=(r-)/m+;r=(r-)%m+;
g[l][r]=edge[k].choose;
getans(edge[k].pre);
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
scanf("%d",&mp[i][j]);
if(!mp[i][j])e1=i,e2=j;
}
}
cntt=INF;
plugdp();
printf("%d\n",cntt);
getans(lastedge);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(!mp[i][j])putchar('x');
else if(g[i][j])putchar('o');
else putchar('_');
}
putchar('\n');
}
return ;
}
BZOJ2595:[Wc2008]游览计划——题解(插头dp)的更多相关文章
- 斯坦纳树 [bzoj2595][wc2008]游览计划 题解
话说挺早就写过斯坦纳树了,不过当时没怎么总结,也不是很理解……现在来个小结吧~ 斯坦纳树就是包含给定点的最小生成树(个人理解权值应当为正). 一般来讲,给定点的数目应该很小吧...于是我们可以用状压D ...
- BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*
BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...
- [bzoj2595][WC2008]游览计划/[bzoj5180][Baltic2016]Cities_斯坦纳树
游览计划 bzoj-2595 wc-2008 题目大意:题目链接.题目连接. 注释:略. 想法:裸题求斯坦纳树. 斯坦纳树有两种转移方式,设$f[s][i]$表示联通状态为$s$,以$i$为根的最小代 ...
- [WC2008]游览计划(状压dp)
题面太鬼畜不粘了. 题意就是给一张n*m的网格图,每个点有点权,有k个关键点,让你把这k个关键点连成一个联通快的最小代价. 题解 这题nmk都非常小,解法肯定是状压,比较一般的解法插头dp,但不太好写 ...
- BZOJ2595 [Wc2008]游览计划 【状压dp + 最短路】
题目链接 BZOJ2595 题解 著名的斯坦纳树问题 设\(f[i][j][s]\)表示点\((i,j)\)与景点联通状况为\(s\)的最小志愿者数 设\(val[i][j]\)为\((i,j)\)需 ...
- BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)
Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 2030 Solved: 986[Submit][Status][ ...
- BZOJ2595[WC2008]游览计划
Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数 ...
- BZOJ2595 WC2008游览计划(斯坦纳树)
斯坦纳树板子题. 考虑状压dp,设f[i][j][S]表示当前在点(i,j)考虑转移,其所在的联通块包含的关键点集(至少)为S的答案. 转移时首先枚举子集,有f[i][j][S]=min{f[i][j ...
- luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)
link 题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价 斯坦纳树模板题 斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e 斯坦纳 ...
随机推荐
- Django模型层:单表操作
一 ORM简介 查询数据层次图解:如果操作mysql,ORM是在pymysq之上又进行了一层封装
- 【Windows定时关机】windows实现定时关机与取消
背景:本人昨晚本来打算将电脑设置为晚上12点 30定时关机,结果写成了:12:30,所以就在刚才,我正玩游戏的时候, 电脑弹出提示:“windows将在一分钟内关闭”,我刚开始一脸懵逼,后来打开昨天敲 ...
- Scrapy爬取美女图片第四集 突破反爬虫(上)
本周又和大家见面了,首先说一下我最近正在做和将要做的一些事情.(我的新书<Python爬虫开发与项目实战>出版了,大家可以看一下样章) 技术方面的事情:本次端午假期没有休息,正在使用fl ...
- Supervisor4.0和python2.7的crit问题,导致python进程阻塞
1.问题原因 Supervisor高版本在守护python2.7的服务时,会crit并报错并倒至进程阻塞(python进程存在,但不在运行)的问题,一般会和字符集有关系 <type 'excep ...
- 《Cocos2d-x游戏开发实战精解》学习笔记4--实战一个简单的钢琴
上一节学习了使用Cocos2d-x播放音乐的方法,但是那种方法一般只适合于播放较大的音乐,而一般比较短小的音乐(如游戏中的打斗.按键音效等)则要通过playEffect来播放.本节使用该方法以及之前学 ...
- less 语法特性翻译稿 - 特性快速预览部分
原文地址 http://lesscss.cn/features/ 概述 作为CSS的一种扩展语法,Less不仅仅向后兼容CSS,新的特性也是基于CSS现有语法.这使得学习Less变得容易,如果你有所怀 ...
- leetcode个人题解——#43 Multiply Strings
思路:高精度乘法就可以了. 有两个错误以前没在意,1.成员属性定义时候不能进行初始化, vector<); 这样隐性调用了函数进行初始化的形式特别要注意,也是错误的: 2.容器类只有分配了空间时 ...
- PowerShell自定义修改远程桌面RDP端口
应朋友的要求写了一个通过PowerShell修改远程桌面(Remote Desktop)端口的脚本,不复杂,启动脚本后有两个选项:1.自定义远程桌面:2.回复远程桌面的默认端口3389 发出来给有用的 ...
- python实现中文验证码识别方法(亲测通过)
验证码截图如下: # coding:utf-8from PIL import Image,ImageEnhanceimport pytesseract#上面都是导包,只需要下面这一行就能实现图片文字识 ...
- Yii2 UploadedFile上传文件
通过 UploadFile::getInstance($model, $attribute); UploadFile::getInstances($model, $attribute); Upload ...
.jpg)
