算法复习——区间dp
感觉对区间dp也不好说些什么直接照搬讲义了2333
例题:
1.引水入城(洛谷1514)
这道题先开始看不出来到底和区间dp有什么卵关系····
首先肯定是bfs暴力判一判可以覆盖到哪些城市····无解直接输出···有解得话就要想想了····
这道题关键是要发现··如果一个蓄水池所在城市可以覆盖到一些沙漠城市···那么这些沙漠城市肯定是一段连续区间····不然假设有一个城市是断开的而两边都被同一个蓄水池流出的水覆盖,这个城市四周的城市都肯定比它矮···(不理解举个反例吧···反正我举不出来)···然后就可以找到每一个蓄水池它对应的可以覆盖的区间···转化成一个关于线段覆盖的区间dp问题·····即可求解(dp方程看代码吧)
另外注意这道题bfs时注意是入队时打标记不然会爆···还有判条件时先判越界没有···
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=;
const int gox[]={,,-,};
const int goy[]={,,,-};
struct node
{
int x,y;
}que[N*N];
struct node1
{
int l,r;
}g[N];
int map[N][N],n,m,tail,head,f[N];
bool visit[N][N];
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline void bfs()
{
head=,tail=;
for(int i=;i<=m;i++)
{
que[++tail].x=;que[tail].y=i;
visit[que[head].x][que[head].y]=true;
}
for(;head<=tail;head++)
{
for(int i=;i<=;i++)
{
visit[que[head].x][que[head].y]=true;
int vx=que[head].x+gox[i];int vy=que[head].y+goy[i];
if(vx<||vx>n||vy<||vy>m||visit[vx][vy]||map[vx][vy]>=map[que[head].x][que[head].y]) continue;
node temp;
temp.x=vx,temp.y=vy;que[++tail]=temp;
visit[temp.x][temp.y]=true;
}
}
}
inline void dfs(int x,int y,int u)
{
visit[x][y]=true;
if(x==n)
g[u].l=min(g[u].l,y),g[u].r=max(g[u].r,y);
for(int i=;i<=;i++)
{
int vx=x+gox[i];int vy=y+goy[i];
if(visit[vx][vy]||vx<||vx>n||vy<||vy>m||map[vx][vy]>=map[x][y]) continue;
dfs(vx,vy,u);
}
}
int main()
{
//("a.in","r",stdin);
memset(f,inf,sizeof(f));
n=R(),m=R();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
map[i][j]=R();
bfs();
int temp=;
for(int i=;i<=m;i++)
if(visit[n][i]==true) temp++;
if(temp!=m)
{
cout<<""<<endl;
cout<<m-temp<<endl;
return ;
}
for(int i=;i<=m;i++)
{
memset(visit,false,sizeof(visit));
g[i].l=m+;g[i].r=;
dfs(,i,i);
}
f[]=;
for(int i=;i<=m;i++)
for(int j=;j<=m;j++)
if(g[j].l<=i&&g[j].r>=i)
f[i]=min(f[i],f[g[j].l-]+);
cout<<""<<endl;
cout<<f[m]<<endl;
return ;
}
2.压缩(bzoj1068)
Description
给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小
写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没
有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程
另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。
Input
输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。
Output
输出仅一行,即压缩后字符串的最短长度。
Sample Input
Sample Output
HINT
在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。
【限制】
100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50
从这道题可以看出:区间dp不只可以用于解决序列的划分、覆盖问题,还可以用于解决序列的压缩、消除问题·····
解决这一类的通法是枚举左右区间然后再在中间枚举断点
接下来引用DaD3zZ的题解,%%%%%
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int f[N][N][],n;
char s[N];
inline bool check(int l,int r)
{
if((r-l+)%==) return false;
int mid=(l+r)/;
for (int i=l; i<=mid; i++) if (s[i]!=s[mid+i-l+]) return false;
return true;
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%s",s+);
n=strlen(s+);
for(int i=n;i>=;i--)
for(int j=i;j<=n;j++)
{
f[i][j][]=f[i][j][]=j-i+;
for(int k=i;k<j;k++)
{
f[i][j][]=min(f[i][j][],min(f[i][k][],f[i][k][])+min(f[k+][j][],f[k+][j][])+);
f[i][j][]=min(f[i][j][],f[i][k][]+j-k);
}
if(check(i,j)) f[i][j][]=f[i][(j+i)/][]+;
if(j-i+==) f[i][j][]=n+;
}
printf("%d\n",min(f[][n][],f[][n][]));
return ;
}
3.字符串折叠(bzoj1090 SCOI2003)
Description
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S) SSSS…S(X个S)。 3. 如果A A’, BB’,则AB A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B) AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
Sample Output
HINT
一个最短的折叠为:2(NEERC3(YES))
这道题和例题2几乎是一样的,同样的区间压缩dp同样的枚举左右区间,同样的枚举断点,同样的判断压缩合法性,并且状态转移还要简单一点·······就不多说了
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int n,f[N][N],m;
char s[N];
inline bool check(int a,int b,int c)
{
if((c-a+)%(b-a+)) return false;
int num=(c-a+)/(b-a+);m=;
for(int i=a;i<=b;i++)
for(int j=i+(b-a+);j<=c;j+=(b-a+))
if(s[j]!=s[i]) return false;
while(num) m++,num/=;
return true;
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%s",s+);n=strlen(s+);
for(int i=n;i>=;i--)
for(int j=i;j<=n;j++)
{
f[i][j]=j-i+;
if(i==j) continue;
for(int k=i;k<j;k++)
{
if(check(i,k,j)) f[i][j]=min(f[i][j],f[i][k]+m+);
f[i][j]=min(f[i][j],f[i][k]+f[k+][j]);
}
}
cout<<f[][n]<<endl;
return ;
}
4.Multiplication Puzzle(zoj1602 poj1651)
The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.
The goal is to take cards in such order as to minimize the total number of scored points.
For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000
If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.
Input
The first line of the input file contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.
Process to the end of file.
Output
Output file must contain a single integer - the minimal score.
Sample Input
6
10 1 50 50 20 5
Sample Output
3650
md这道智障题充分证明我在区间dp上还有待修炼····注意要交这道题去zoj交,poj数据太tm水了···
这道题其实很类似最开始讲义里提到的消除回文子串问题··甚至简单得多··也是一道区间消除问题···
考虑到1,n是不能被消除的,我用f[i][j]表示消除i到j之间的数字最少需要多少分数(注意是之间),枚举中间点k,这里k可以看成最后一个消除的点,推出
f[i][j]=max{f[i][j],f[i][k]+f[k][j]+num[k]*num[i]*num[j]}
注意初始化时f[i][i]=f[i][i+1]=0,其他等于inf········
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int n,num[N],f[N][N];
const int inf=0x3f3f3f3f;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
int main()
{
//freopen("a.in","r",stdin);
while(scanf("%d",&n)!=EOF)
{
memset(f,inf,sizeof(f));
for(int i=;i<=n;i++) num[i]=R(),f[i][i+]=f[i][i]=;
for(int i=n-;i>=;i--)
for(int j=i+;j<=n;j++)
for(int k=i+;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]+num[i]*num[k]*num[j]);
cout<<f[][n]<<endl;
}
return ;
}
5.Dire Wolf(hdu5115)
Problem Description
Dire wolves look like normal wolves, but these creatures are of nearly twice the size. These powerful beasts, 8 - 9 feet long and weighing 600 - 800 pounds, are the most well-known orc mounts. As tall as a man, these great wolves have long tusked jaws that look like they could snap an iron bar. They have burning red eyes. Dire wolves are mottled gray or black in color. Dire wolves thrive in the northern regions of Kalimdor and in Mulgore.
Dire wolves are efficient pack hunters that kill anything they catch. They prefer to attack in packs, surrounding and flanking a foe when they can.
— Wowpedia, Your wiki guide to the World of Warcra
Matt, an adventurer from the Eastern Kingdoms, meets a pack of dire wolves. There are N wolves standing in a row (numbered with 1 to N from left to right). Matt has to defeat all of them to survive.
Once Matt defeats a dire wolf, he will take some damage which is equal to the wolf’s current attack. As gregarious beasts, each dire wolf i can increase its adjacent wolves’ attack by bi. Thus, each dire wolf i’s current attack consists of two parts, its basic attack ai and the extra attack provided by the current adjacent wolves. The increase of attack is temporary. Once a wolf is defeated, its adjacent wolves will no longer get extra attack from it. However, these two wolves (if exist) will become adjacent to each other now.
For example, suppose there are 3 dire wolves standing in a row, whose basic attacks ai are (3, 5, 7), respectively. The extra attacks bi they can provide are (8, 2, 0). Thus, the current attacks of them are (5, 13, 9). If Matt defeats the second wolf first, he will get 13 points of damage and the alive wolves’ current attacks become (3, 15).
As an alert and resourceful adventurer, Matt can decide the order of the dire wolves he defeats. Therefore, he wants to know the least damage he has to take to defeat all the wolves.
Input
The second line contains N integers ai (0 ≤ ai ≤ 100000), denoting the basic attack of each dire wolf.
The third line contains N integers bi (0 ≤ bi ≤ 50000), denoting the extra attack each dire wolf can provide.
Output
Sample Input
3
3 5 7
8 2 0
10
1 3 5 7 9 2 4 6 8 10
9 4 1 2 1 2 1 4 5 1
Sample Output
Case #2: 74
In the first sample, Matt defeats the dire wolves from left to right. He takes 5 + 5 + 7 = 17 points of damage which is the least damage he has to take.
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int a[N],b[N],n,T,f[N][N];
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline int trans(int a)
{
if(a<) return ;
else return a;
}
int main()
{
//freopen("a.in","r",stdin);
T=R();
for(int t=;t<=T;t++)
{
memset(f,inf,sizeof(f));
memset(b,,sizeof(b));
printf("Case #%d: ",t);
n=R();
for(int i=;i<=n;i++) a[i]=R();
for(int i=;i<=n;i++) b[i]=R();
for(int i=;i<=n+;i++)
f[i][i]=f[i][i+]=;
for(int i=n-;i>=;i--)
for(int j=i+;j<=n+;j++)
for(int k=i+;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]+b[i]+b[j]+a[k]);
printf("%d\n",f[][n+]);
}
return ;
}
6.Two Rabbits(hdu4745)
Problem Description
The rabbits jumped from one stone to another. Tom always jumped clockwise, and Jerry always jumped anticlockwise.
At the beginning, the rabbits both choose a stone and stand on it. Then at each turn, Tom should choose a stone which have not been stepped by itself and then jumped to it, and Jerry should do the same thing as Tom, but the jumping direction is anti-clockwise.
For some unknown reason, at any time , the weight of the two stones on which the two rabbits stood should be equal. Besides, any rabbit couldn't jump over a stone which have been stepped by itself. In other words, if the Tom had stood on the second stone, it cannot jump from the first stone to the third stone or from the n-the stone to the 4-th stone.
Please note that during the whole process, it was OK for the two rabbits to stand on a same stone at the same time.
Now they want to find out the maximum turns they can play if they follow the optimal strategy.
Input
For each test cases, the first line contains a integer n denoting the number of stones.
The next line contains n integers separated by space, and the i-th integer ai denotes the weight of the i-th stone.(1 <= n <= 1000, 1 <= ai <= 1000)
The input ends with n = 0.
Output
Sample Input
1
4
1 1 2 1
6
2 1 1 2 1 3
0
Sample Output
4
5
For the second case, the path of the Tom is 1, 2, 3, 4, and the path of Jerry is 1, 4, 3, 2.
For the third case, the path of Tom is 1,2,3,4,5 and the path of Jerry is 4,3,2,1,5.
求环的最长不连续回文子串的模板题····详见http://blog.csdn.net/hcbbt/article/details/18949581
代码:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=;
int num[N],f[N][N],n;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
int main()
{
//freopen("a.in","r",stdin);
while(true)
{
n=R();if(!n) break;
memset(f,,sizeof(f));
for(int i=;i<=n;i++) num[i]=R(),f[i][i]=;
for(int l=;l<n;l++)
for(int i=;i+l<=n;i++)
{
int j=l+i;
f[i][j]=max(max(f[i+][j],f[i][j-]),f[i+][j-]+(num[i]==num[j]?:));
}
int ans=;
for(int i=;i<=n;i++) ans=max(ans,f[][i]+f[i+][n]);
cout<<ans<<endl;
}
return ;
}
算法复习——区间dp的更多相关文章
- 算法笔记--区间dp
1.石子归并问题 dp[i][j]表示区间i到j合并所需的最小花费. 先求出小区间的最小花费,再转移到大的区间. 转移方程:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1] ...
- 算法复习——数位dp
开头由于不知道讲啥依然搬讲义 对于引入的这个问题,讲义里已经很清楚了,我更喜欢用那个建树的理解···· 相当于先预处理f,然后从起点开始在树上走··记录目前已经找到了多少个满足题意的数k,如果枚举到第 ...
- 算法复习——数位dp(不要62HUD2089)
题目 题目描述 杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司 ...
- 算法复习——树形dp
树形dp的状态转移分为两种,一种为从子节点到父节点,一种为父节点到子节点,下面主要讨论子节点到父亲节点的情况: 例题1(战略游戏): 这是一道典型的由子节点状态转移到父节点的问题,而且兄弟节点之间没有 ...
- 算法复习——背包dp
1.01背包 二维递推式子: 代码: ;i<=n;i++) ;x--) ][x-w[i]]+c[i],f[i-][x]); ][x]; printf("%d",f[n][m] ...
- 洛谷P1220 关路灯 题解 区间DP
题目链接:https://www.luogu.com.cn/problem/P1220 本题涉及算法:区间DP. 我们一开始要做一些初始化操作,令: \(p[i]\) 表示第i个路灯的位置: \(w[ ...
- 算法提高 矩阵乘法 区间DP
这是神题,n <= 1000,如果是极限数据普通的n^3区间DP怎么可能过?可偏偏就过了. 刘汝佳大哥的训练指南上面说的存在nlgn的算法解决矩阵链乘问题,可是百度都找不到.... AC代码 # ...
- 区间DP与贪心算法的联系(uav Cutting Sticks && poj Fence Repair(堆的手工实现))
由于,这两题有着似乎一样的解法所以将其放在一起总结比較,以达到更好的区分二者的差别所在. 一.区间DP uva的Cutting Sticks是一道典型的模板题. 题目描写叙述: 有一根长度为l的木棍, ...
- 蓝桥 ADV-232 算法提高 矩阵乘法 【区间DP】
算法提高 矩阵乘法 时间限制:3.0s 内存限制:256.0MB 问题描述 有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要 ...
随机推荐
- [论文理解] Connectionist Text Proposal Network
Connectionist Text Proposal Network 简介 CTPN是通过VGG16后在特征图上采用3*3窗口进行滑窗,采用与RPN类似的anchor机制,固定width而只预测an ...
- cv2.getPerspectiveTransform 透视变换
简介 透视变换(Perspective Transformation)是将成像投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping).如图1,通过透 ...
- Problem D: 小平查密码
Problem D: 小平查密码 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 194 Solved: 40[Submit][Status][Web ...
- 题解 P5051 【[COCI2017-2018#7] Timovi】
看到这道题目,数据范围,心凉了一大截 这是没开O2的 而这是开了O2的 emm……本蒟蒻也无言以对呀 好了,回归正题,看到题目的标签,高性能,自然而然地想到了快读 相信做这题的大佬们一定知道吧! 快读 ...
- linux ecrypt decrypt
reference ecrypt vickey | openssl enc -aes-256-cbc -a -salt -pass pass:wu decrypt echo U2FsdGVkX1+Hn ...
- 【SAM】loj#6401. 字符串
网上有篇题解写的是线段树合并维护求值? 题目描述 有一个只包含小写字母,长度为 $n$ 的字符串 $S$ .有一些字母是好的,剩下的是坏的. 定义一个子串 $S_{l\ldots r}$是好的,当且仅 ...
- redis学习笔记(1)
最近在学习redis,做了比较详细的学习笔记,分享给大家,欢迎一起讨论和学习 第一部分,简单介绍redis 和 redis的基本操作 NoSQL的特点 : 数据库种类繁多,但是一个共同的特点都是去掉关 ...
- 解决linux不能解压rar格式压缩包
1download rarlinux-x64-5.3.0.tar.gz data package 2.tar xvf rarlinux-64-5.3.0.tar.gz 3. cd rar and th ...
- 【mysql】[Err]1267 - Illegal mix of collations(utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) for operation ‘=
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
- C# NotifyIcon 托盘控件
右下角以图标形式显示,双击图标显示界面,最小化界面时不显示在任务栏. 第一步:在界面上添加NotifyIcon控件. 第二步:设置notifyIcon1的属性,添加图标,将Visible设为true. ...