状态压缩DP----HDU4049 Tourism Planning
状态压缩动态规划感觉都不是那么好写,看网上的人说这题是2011年ACM/ICPC中的水题,暗地里感觉很是惭愧啊(花了将近4个小时),结果还算是勉勉强强地弄出来了。
与往常一样,先说说题目的意思和思路,再给出代码,最后分享出代码比较精髓的地方(有的话),另这随笔主要目的是方便自己以后使用,当然很是欢迎大家指出错误和批评。那就开始了:
题目说的是有一群小伙伴去旅游,某个人对某以特定的城市有一定的兴趣,并且多人一同去还有奖励,当然门票还是要的嘛。
输入:N(小伙伴的个数),M(城市的个数)紧接着的一行是各个城市的门票价格,然后是一个N*M的矩阵表示第i名游客对j城市的感兴趣度,最后还有一个N*N的矩阵表示若i旅客与j旅客结伴出行的话可以得到的奖金。特别注意的是游客可以中间插入,也可以中途离开,但若是中途离开以后就不得在后面的观光中出现.
输出:最后的结果若<=0,那么就输出"STAY HOME"。
思路还是状态压缩嘛,具体来讲就是用一个叫DP[i]的数组记录从开始的城市到当前城市中总共值中选出最大的,在用一个temp[i]数组来保存相应的DP[i]值,为后面的DP做准备,然后交替进行,期间必须保证离队以后的人不可以再次入队,这点怎么保证呢?
for(int i=1;i<=M;i++)
{
for(int j=0;j<bit;j++) dp[j]=MIN;
for(int j=0;j<bit;j++)
{
int weight=calculate(j,i);
for(int k=j;k<bit;k=(k+1)|j)
{
dp[j]=max(dp[j],temp[k]+weight);
}
}
for(int j=0;j<bit;j++) temp[j]=dp[j];
}
就用这几行代码就可以搞定了。第一个for循环是从1到M的城市,第二行是对于城市i的状态为j,第三行是总结出从1到i可以达到的最大值,中间的temp一直记录这些最大值,这与滚动数组非常类似。为什么这样写就能保证中途掉队的的在以后就一定加不进来呢?那么你可以仔细看看第三个for循环k是如何增加的(k=(k+1)|j)保证了变化后的k中一定包含有j的状态,也就是说参观第i-1座城市的人一定>=参观i城市时候的人,并且i城市的人在i-1城市的一定有,然后大家可以用类似于归纳法的思想来证明这种思路是正确的。
不罗嗦了,直接上代码:
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std;
#define INFI (1<<10)+20
#define MIN -2139062144
int N,M;
int dp[INFI],bonus[][],cost[];
int inter[][],temp[INFI]; inline int max(int a,int b)
{
if(a>b) return a;
return b;
}
int calculate(int k,int v)
{
int sieze[],num=,result=;
for(int i=;i<N;i++) if(k&(<<i)) sieze[++num]=i;
for(int i=;i<=num;i++)
{
result+=inter[sieze[i]][v];
for(int j=i+;j<=num;j++) result+=bonus[sieze[i]][sieze[j]];
}
return result-num*cost[v];
}
int DP()
{
int bit=<<N;
for(int i=;i<bit;i++) temp[i]=;
for(int i=;i<=M;i++)
{
for(int j=;j<bit;j++) dp[j]=MIN;
for(int j=;j<bit;j++)
{
int weight=calculate(j,i);
for(int k=j;k<bit;k=(k+)|j)
{
dp[j]=max(dp[j],temp[k]+weight);
}
}
for(int j=;j<bit;j++) temp[j]=dp[j];
}
int result=-;
for(int i=;i<bit;i++) result=max(result,temp[i]);
if(result<=) printf("STAY HOME.\n");
else printf("%d\n",result);
}
int main()
{ while(scanf("%d %d",&N,&M),(N||M))
{
for(int i=;i<=M;i++)
scanf("%d",&cost[i]); for(int i=;i<N;i++)
for(int j=;j<=M;j++)
scanf("%d",&inter[i][j]); for(int i=;i<N;i++)
for(int j=;j<N;j++)
scanf("%d",&bonus[i][j]); DP();
} return ;
}
状态压缩DP----HDU4049 Tourism Planning的更多相关文章
- HOJ 2226&POJ2688 Cleaning Robot(BFS+TSP(状态压缩DP))
Cleaning Robot Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4264 Accepted: 1713 Descri ...
- hoj2662 状态压缩dp
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
- POJ 3254 Corn Fields(状态压缩DP)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4739 Accepted: 2506 Descr ...
- [知识点]状态压缩DP
// 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...
- HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP
题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...
- DP大作战—状态压缩dp
题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...
- 状态压缩dp问题
问题:Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Ev ...
- BZOJ-1226 学校食堂Dining 状态压缩DP
1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...
- Marriage Ceremonies(状态压缩dp)
Marriage Ceremonies Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu ...
- HDU 1074 (状态压缩DP)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074 题目大意:有N个作业(N<=15),每个作业需耗时,有一个截止期限.超期多少天就要扣多少 ...
随机推荐
- JMeter启动时显示Could not open/create prefs root node Software\JavaSoft\Prefs at root 0X80000002
在windows 7上启动jmeter时,提示错误: Java.util.prefs.WindowsPreferences <init> WARNING: Could not open/c ...
- 发现一个github的奇葩设定
commit时留下的邮箱,会显示在github的提交记录里,然后居然自动找服务器上的这个邮箱注册的人,显示这个用户名.
- sql server中类似oracle中decode功能的函数
sqlserver 2008 写法 select t.PROJECTNAME, t.BUILDCONTENTSCALE, CASE t.PROJECTLEVEL ' THEN '国家重点' ' THE ...
- c# HttpWebResponse 调用WebApi
public static class WebApiCaller { public static string HttpPost(string url, string body) { try { // ...
- MSSQL使用sqlbulkcopy批量插入数据
具体代码如下: /// <summary> /// 批量插入数据到BayonetZipFailedPic表 /// </summary> /// <param name= ...
- c++ 浅谈 new 的使用
实例用法: 创建对象: class U_Ptr smart; U_Ptr* ptr = new U_Ptr(); class U_Ptr smart(new U_Ptr(p)); int *p = n ...
- linux下创建与删除用户详细步骤 ***
linux下用户的操作还是相对容易理解的,基本操作如下: 1.新增用户 只有root用户能创建新用户 #useradd user1 新建后将会在/home目录下生成一个与用户名相同的用户主目录.同时会 ...
- 严谨的程序案例Api
文档 功能 同步推荐关系 接口方法 syncRelation 参数描述 OriginalUsername 查询的用户用户名 RecommandUsername 推荐人用户名 返回值 status 1成 ...
- 微信企业号支付个人php实现
导语:分销商,微商提现怎么提? 直接用微信支付. 实现如下: 微信支付配置 /*微信支付*/ 'PAY_WEIXIN' => array( 'appid' => 'XXXX', 'apps ...
- java实现递归(1)
1.递归算法基本思路: Java递归算法是基于Java语言实现的递归算法.递归算法是一种直接或者间接调用自身函数或者方法的算法.递归算法实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法表 ...