博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
枚举、模拟、递推
阅读量:6262 次
发布时间:2019-06-22

本文共 3371 字,大约阅读时间需要 11 分钟。

枚举、模拟、递推

一、枚举模拟递推

  1. 状态空间:一个实际问题的各种可能情况构成的集合

  2. 递推和递归:程序遍历状态空间

    枚举和模拟:将状态空间按照一定的顺序"直接"交给程序进行遍历的算法

  3. 按规模大小

枚举形式 一般遍历方式
多项式 循环、递推
指数 递归、位运算
排列 递归、c++ next_permutation
组合 递归+剪枝
  1. Strange Towers of Hanoi (POJ1958)

n个盘子4座塔的Hanoi问题至少需要多少步?(1<=n<=12)

分析:

n盘3塔: \(d[n] = 2*d[n-1]+1\) => \(d[n] = 2^n - 1\)

  1. 前n-1盘子 A -> B
  2. 第n盘子 A -> C
  3. 前n-1盘子 B -> C

n盘4塔:\(f[n] = min_{1\leq i<n}\{2*f[i] + d[n-i]\}\)

  1. 把i个盘子 A->B (四塔模式)
  2. 把n-i个盘子 A->D (三塔模式)
  3. 把i个盘子 B-> D (四塔模式)
  4. 考虑所有可能i取最小值

题解:

#include
#include
using namespace std;int main(){ int f[13] = {0}; int minstep,step; f[1] = 1; for(int n=2;n<=12;n++){ minstep = 0x3f3f3f3f; step=0; for(int i=1;i

二、前缀和

  1. 前缀和:前面i个数的总和

  2. 对于一个给定的数列A,它的前缀和数列S

    \(s[i] = \sum_{j=1}^i A[j]\)

    数列区间数的和 = 前缀和相减

    \(sum(l,r) = \sum_{i=l}^r A[i] = S[r]-S[l-1]\)

  3. 可以扩展到二维数组中

例题:

  1. 激光炸弹(BZOJ1218)

一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。现在地图上有n(N<=10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值。激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破范围,即那个边长为R的正方形的边必须和x,y轴平行。若目标位于爆破正方形的边上,该目标将不会被摧毁。

输入输出格式:

输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示xi,yi,vi

输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

输入样例:

2 1

0 0 1
1 1 1

输出样例:

1

分析:

二维数组前缀和:一定区间里价值之和

二维前缀和事例图片

\(S[i,j] = S[i-1,j] + S[i,j-1]-S[i-1,j-1]+A[i,j]\)

边长R的正方形的价值(ij为正方形的右下角)

\(P[i,j] = S[i,j] - S[i-R,j] - S[i,j-R] + S[i-R,j-R]\)

然后枚举正方形右下角找最大值

错误题解:(TLE MLE一堆 用于理解)

#include
#define N 5000+5using namespace std;int A[N][N]={0}; //main函数里定义上限719 X 719int S[N][N]={0};int P[N][N]={0};int main(){ int n,r,a,b,m; cin>>n>>r; m= 0; while(n--){ int x,y,v; cin>>x>>y>>v; A[x][y] = v; if(m
5000)?5000:m+r; for(int i=0;i
max) max=P[i][j]; } } cout<

题解:

#include
#define N 5000+5using namespace std;int A[N][N]={0}; int main(){ int n,r,a,b,c,m; cin>>n>>r; m= 0; // 找个上限 缩短下运行时间 while(n--){ int x,y,v; cin>>x>>y>>v; A[x+1][y+1] += v; if(m
5000)?5000:m+r; for(int i=1;i<=m;i++){ for(int j=1;j<=m;j++){ a = (i-1<0)?0:i-1; b = (j-1<0)?0:j-1; A[i][j] += A[a][j]+A[i][b]-A[a][b]; } } int max = 0; for(int i=1;i<=m;i++){ for(int j=1;j<=m;j++){ a = (i-r<0)?0:i-r; b = (j-r<0)?0:j-r; c= A[i][j] - A[a][j] - A[i][b] + A[a][b]; if(c>max) max=c; } } cout<
  1. Tallest Cow(POJ3263)

给出N头牛的身高,和M对关系(ai与bi可以相互看见。即他们中间的牛都比他们矮)。已知最高的牛为第P头,身高为H。求每头牛的身高最大可能是多少。( \(1 \leq N,M \leq 10^4, 1 \leq H \leq 10^6\) )

输入样例:

9 3 5 5

1 3
5 3
4 3
3 7
9 8

输出样例:

5

4
5
3
4
4
5
5
5

分析:

朴素解法:数组C初始化0 ,ai与bi之间的数减一 最后设C[P] = 0 即Hi = H+C[i] \(O(NM)\)

前缀和:把对一个区间的操作转化为左右两个端点的操作,再通过前缀和得到原问题的解

​ 数组D初始化0,D[ai+1]-=1,D[bi]+=1 最后 \(C[i] = \sum_{j=1}^iD[j]\) \(O(N+M)\)

题解:

#include
#include
using namespace std;map
,bool> existed; //处理重复的成对关系int c[10010],d[10010];int main(){ int n,p,h,m; cin>>n>>p>>h>>m; for(int i=1;i<=m;i++){ int a,b,t; cin>>a>>b; if(a>b){t=a;a=b;b=t;} if(existed[make_pair(a,b)])continue; d[a+1]--;d[b]++; existed[make_pair(a,b)] = true; } for(int i=1;i<=n;i++){ c[i] = c[i-1] + d[i]; cout<
<

转载于:https://www.cnblogs.com/wendiudiu/p/10762111.html

你可能感兴趣的文章
aaronyang的百度地图API之LBS云与.NET开发 Javascript API 2.0【基本地图的操作】
查看>>
Java Nio 多线程网络下载
查看>>
C++不让程序一闪而过
查看>>
C# 中的枚举类型 enum (属于值类型)
查看>>
[Debug] Use Snippets to Store Behaviors in Chrome DevTools
查看>>
【Java面试题】3 Java的"=="和equals方法究竟有什么区别?简单解释,很清楚
查看>>
通用性好的win2003序列号: (推荐先用这个里面的)
查看>>
Chromium Embedded Framework中文文档 (升级到最新的Chrome)
查看>>
WPF Command CanExecute 的执行逻辑
查看>>
更为快捷的Excel操作方式 快捷键 Alt使用技巧动画图解
查看>>
程序员们最易犯的10种错误
查看>>
面试必考题!你知道CSS实现水平垂直居中的第10种方式吗?
查看>>
超多惊喜!苹果 iPhone8 最新渲染图曝光
查看>>
你想要不想要?OPPO R11将搭配前后2000万像素镜头!
查看>>
Payara基金会发布全面支持MicroProfile 2.0的5.183版
查看>>
360金融宣布采用新会计准则 2018年前三季度净利11亿
查看>>
非洲小哥见到马云 竟然提了这样的要求?
查看>>
收购大战:高通承诺将年收入增长率提至8%
查看>>
宁夏:科技创新激活高质量发展动能
查看>>
毕马威:中国消费未现降级 进一步增长潜力巨大
查看>>