[GDOI2014]拯救莫莉斯 状压DP
题面:
莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场。
圣域的地图可以看成是一个n*m的矩阵。每个整数坐标点(x , y)表示一座城市( 1\le x\le n,1\le y\le m1≤x≤n,1≤y≤m )。两座城市间相邻的定义为:对于城市(Ax, Ay)和城市(Bx, By),满足 (Ax - Bx)^2 + (Ay - By)^2 = 1(Ax−Bx)2+(Ay−By)2=1 。
由于圣域的石油贸易总量很大,莫莉斯意识到不能让每笔石油订购单都从同一个油库里发货。为了提高效率,莫莉斯·乔决定在其中一些城市里建造油库,最终使得每一个城市X都满足下列条件之一:
1.该城市X内建有油库,
2.某城市Y内建有油库,且城市X与城市Y相邻。
与地球类似,圣域里不同城市间的地价可能也会有所不同,所以莫莉斯想让完成目标的总花费尽可能少。如果存在多组方案,为了方便管理,莫莉斯会选择建造较少的油库个数。
n * m <= 50, m < n
简单题意:
有一个带权值的矩阵,取一个方格的代价为它的权值,取一个方格时可以给它自己和上下左右的格子打上标记,求最小代价(代价相同取最少数量的方格)使得整个矩阵都被标记。
题解:
观察到n * m <=50,m < n,也就是说m最大也只能是7,看见这么小的数,,,显然这就是个状压啊!
第一眼貌似就是很套路的状压,,,
不过貌似还是有不同的,
唯一的不同在于:一行受上一行和下一行的同时影响,也就是说当前行可以不满足全都标记,因为后来还可以有别的城市来标记它,
因此枚举i和i-1和i-2行的状态,合法条件为:必须使得i-1合法,因此i-1要是再不合法的话以后都不能合法了,,,
同时将f初始化为极大值,这样的话就无需判断i-2是否合法,因为不合法的话将不会被更新,那么值就是inf,也就不会被当做决策了
但是观察到我们并不方便临时计算每个状态的各种数据,因此我们先预处理一遍,处理出每一行的每一个状态对应的城市数和代价,
分别记为num[i][j].num 和 num[i][j].cost
设f[i][j][k].cost 为第i行状态为j,第i-1行状态为k的最小代价,f[i][j][k].num表示在最小代价的基础上的最少城市数,
那么我们的合法条件显然为:if(((k | j | l | (k << 1) | (k >> 1)) & all) == all),其中k为i-1行,j为i行,l为i-2行,
all为2 ^ m - 1 , 也就是2进制下的 111111(m个1)
& all用于消除高于m位的1,以免对ans产生影响。
如果==all就表示合法,因为| j 和| l 表示用上下的城市来标记k一次,然后k << 1 和k >> 1就是用左右的城市来标记一次
那么有转移方程:
if(f[i-1][k][l] + num[i][j] <= f[i][j][k])
f[i][j][k]=f[i-1][k][l] + num[i][j];
其中
node operator + (node a,node b)
{
a.cost += b.cost;
a.num += b.num;
return a;
} bool operator <= (node a,node b)
{
if(a.cost < b.cost) return true;
else if(a.cost == b.cost && a.num < b.num) return true;
else return false;
}
最后统计ans的时候的合法条件为第n行合法。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 300
#define inf 80000000
#define ac 50
int n,m,all;
int s[ac][ac];
struct node{
int cost,num;
}f[ac][AC][AC],num[ac][AC],ans;
/*因为n * m <= 50 , m < n,所以m实际上是很小的,m <= sqrt(50),
因此预处理出对于每一行,任意状态下的油库个数和代价,在代价相同的基础上取油库最少
一定要注意状态从0开始枚举!*/
node operator + (node a,node b)
{
a.cost += b.cost;
a.num += b.num;
return a;
} bool operator <= (node a,node b)
{
if(a.cost < b.cost) return true;
else if(a.cost == b.cost && a.num < b.num) return true;
else return false;
} void pre()
{
scanf("%d%d",&n,&m);
all=( << m) - ;
for(R i=;i<=n;i++)
for(R j=;j<=m;j++)
scanf("%d",&s[i][j]);
for(R i=;i<=n;i++)//枚举行,看做常数?
for(R j=;j<=all;j++)//枚举状态
for(R k=;k<=m;k++)//看做常数?
if(j & ( << (m - k))) //预处理,,,但是看上去复杂度很高啊
{
num[i][j].cost+=s[i][k];
num[i][j].num++;
}
ans.cost=inf , ans.num=inf;
} void work()
{
for(R i=;i<=all;i++) f[][i][]=num[][i];
for(R i=;i<=all;i++)
for(R j=;j<=all;j++)
{
f[][i][j].cost = inf;
if(((j | i | (j << ) | (j >> )) & all) == all)
f[][i][j]=f[][j][] + num[][i];
}
for(R i=;i<=n;i++)//枚举行
for(R j=;j<=all;j++)//枚举当前行
for(R k=;k<=all;k++)//枚举上一行状态
{
f[i][j][k].cost = inf;
f[i][j][k].num = inf;
for(R l=;l<=all;l++)//枚举上上行状态
if(((k | j | l | (k << ) | (k >> )) & all) == all)//全都更新一遍,至于如何解决二次传播的方法,,,用原版就好了啊
if(f[i-][k][l] + num[i][j] <= f[i][j][k])
f[i][j][k]=f[i-][k][l] + num[i][j];
}
for(R i=;i<=all;i++)
{
for(R j=;j<=all;j++)
if(((i | j | (i << ) | (i >> )) & all) == all)
if(f[n][i][j] <= ans) ans=f[n][i][j];
}
printf("%d %d\n",ans.num,ans.cost);
}//因为受两行影响,而且是上下两行,,,,所以当前行不用满足,保证上一行满足即可???
//因为上一行还不满足的话就满足不了了
int main()
{
// freopen("in.in","r",stdin);
pre();
work();
// fclose(stdin);
return ;
}
[GDOI2014]拯救莫莉斯 状压DP的更多相关文章
- 拯救莫莉斯 状压dp
题目大意:每个点有费用,要求选出花费最少的一些点,使得全部点都满足:他被选或与他相邻的任意点被选. 没看清数据范围233333 和翻格子游戏一样,考虑上中下三行,可行才能转移 f[i][j][k]表示 ...
- [GDOI2014]拯救莫莉斯
题目描述 莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场. 圣域的地图可以看成是一个n*m的矩阵.每个整数坐标点(x , y)表示一座城市吗,两座城市间相邻 ...
- 【[GDOI2014]拯救莫莉斯】
可能我的状态比较鬼畜,应该没有人这么写 设\(dp[i][j][k]\)表示在第\(i\)行,放置油库的状态为\(j\),实际上周围已经有油库或者本身有油库的状态为\(k\)的时候的最小花费 由于我们 ...
- 拯救莫莉斯[GDOI2014]
时间限制:1s 内存限制:256MB 问题描述 莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场. 圣域的地图可以看成是一个n*m的矩阵.每个整数坐标 ...
- [ GDOI 2014 ] 拯救莫莉斯
\(\\\) \(Description\) 有一个 \(N\times M\) 的网格,每个格点都有权值,图是四连通的. 现在选择一个点集,使得每个格点要么被选中,要么连通的点之一被选中. 求这个点 ...
- luogu3888 GDOI2014拯救莫里斯 (状压dp)
题目描述 莫莉斯·乔是圣域里一个叱咤风云的人物,他凭借着自身超强的经济头脑,牢牢控制了圣域的石油市场. 圣域的地图可以看成是一个n*m的矩阵.每个整数坐标点(x , y)表示一座城市\(( 1\le ...
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- nefu1109 游戏争霸赛(状压dp)
题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...
- poj3311 TSP经典状压dp(Traveling Saleman Problem)
题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...
随机推荐
- 「日常训练」Skills(Codeforce Round #339 Div.2 D)
题意(CodeForces 614D) 每个人有\(n(n\le 10^5)\)个技能,技能等级都在\([0,10^9]\)的范围,每个技能有一个当前等级,所有技能的最高等级都为A.一个人的力量被记做 ...
- 一种新的自动化 UI 测试解决方案 Airtest Project
今天分享一个自动化UI测试工具airtest——一款网易出品的基于图像识别面向游UI测试的工具,也支持原生Android App基于元素识别的UI自动化测试.主要包含了三部分:Airtest IDE. ...
- Appium(Python)驱动手机Chrome浏览器
手机Chrome浏览器访问淘宝H5与在电脑上访问淘宝H5是一摸一样的: 第一种方法: 直接在电脑Chrome浏览器上打开F12: 第二种方法: 手机连接电脑后, 在手机Chrome浏览器上打开淘宝H5 ...
- 题解 CF682C 【Alyona and the Tree】
简单搜索题,我们每找到一组不满足题目给出条件的点和边就将其整个子树删除,然后最终答案加上该子树的大小即可.注意,搜索的时候如果当前的边权和sum已经为负了,应该将其改为0(可以想想为什么) 注:题目翻 ...
- Oracle启动与关闭数据库实例
Oracle数据库启动实例分为3个步骤: 启动实例 加载数据库 打开数据库 通用模式: STARTUP [ nomount | mount | open | force ] [resetrict] ...
- 【转】unity3d 资源文件从MAX或者MAYA中导出的注意事项
转自游戏开发主席 1.首先,Unity3d 中,导出带动画的资源有2种导出方式可以选择: 1) 导出资源时,只导出一个文件,保留模型,骨骼和所有的动作帧(把所有的动作,比如idle,atta ...
- 3.配置HDFS HA
安装zookeeper下载zookeeper编辑zookeeper配置文件创建myid文件启动zookeeper配置HDFS HA配置手动HA配置自动HA启动HDFS HA namenode负责管理整 ...
- wpa_supplicant上行接口浅析
摘自http://blog.csdn.net/fxfzz/article/details/6176414 wpa_supplicant提供的接口 从通信层次上划分, 上行接口:wpa_supplica ...
- The Uncle_b's First Love
Description ACM成立大会之后,uncle_b被其中一个大一女孩深深地吸引,但腼腆的B叔又不知道如何去表达自己内心的想法,经calmound神的指导,B叔决定写封情书给对方.他从Tamar ...
- android仿系统Launcher界面,实现分屏,左右滑动效果(ViewSwitcher)
ViewSwitcher代表了视图切换组件, 本身继承了FrameLayout ,可以将多个View叠在一起 ,每次只显示一个组件.当程序控制从一个View切换到另个View时,ViewSwitche ...