线性DP
线性DP
线性DP要解决的问题多和最长上升子序列有关,而题目给出的数据多未排序,很难观察出要求的答案。题目中每个元素多有两个变量,可以尝试着将其中一个变量按照升序或者降序排好序,这样往往方便观察,容易找到思路。
一.最长上升子序列
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int f[N],h[N],i,p[N],n,j;
void out(int x){
if(x==0)return;
out(p[x]);
cout<<h[x]<<' ';
return;
}
int main(){
int x,st,ans=0;
while(scanf("%d",&x)!=EOF)h[++n]=x;
for(i=1;i<=n;i++){
f[i]=1;
for(j=1;j<i;j++){
if(h[i]>h[j]&&f[i]<f[j]+1){
f[i]=f[j]+1;
p[i]=j;
// 若是第j个高度大于第i个则可将j加入该上升子序列,变为以j结束的子序列
}
}
if(ans<f[i]){
ans=f[i];
st=i;
}
}
cout<<"max="<<ans<<endl;
out(st);
return 0;
}
二.友好城市
题目描述:
Palmis国有一条横贯东西的大河,何有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。
每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。
编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不想交的情况下,被批准的申请尽量多。
输入格式:
第1行,一个整数N(1 <= N <= 5000),表示城市数。 第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0 <= xi <= 10000)
输出格式:
仅一行,输出一个整数,表示政府所能批准的最多申请数。
开始做的时候,感觉可以一个一个航线加进来,若是该航线与已加进来的航线交叉,则不加入此航线。
但这样做太麻烦了并且结果往往不是正解,所以我开始转变思路:
若是按照南岸坐标从小到大排列,两条航线若不相交,则可看作是一个上升序列,因此题目就变成了求最长上升子序列。这样问题就迎刃而解了
完整代码:
#include<bits/stdc++.h>
using namespace std;//01bb
#define N 5050
int f[N],j;
struct stu{
int x,y;
bool operator <(const stu &stu1)const{
return x<stu1.x;
}
}s[N];
int n,i,ma;
int main(){
cin>>n;
for(i=1;i<=n;i++){
scanf("%d%d",&s[i].x,&s[i].y);
ma=max(ma,s[i].y);
}
sort(s+1,s+1+n);
for(i=1;i<=n;i++){
f[i]=1;
for(j=1;j<i;j++){
if(s[i].y>s[j].y&&f[i]<f[j]+1){
f[i]=f[j]+1;
}
}
}
int ma=0;
for(i=1;i<=n;i++){
ma=max(ma,f[i]);
}
cout<<ma;
return 0;
}
//f[j]表示以j结尾的最长上升子序列的长度,最长的上升子序列不一定以n结尾,所以要遍历求出最大值。
三.打鼹鼠
题目描述:
鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的。根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个nn的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气。你可以控制一个机器人来打鼹鼠,如果i时刻鼹鼠在某个网格中出现,而机器人也处于同一网格的话,那么这个鼹鼠就会被机器人打死。而机器人每一时刻只能够移动一格或停留在原地不动。机器人的移动是指从当前所处的网格移向相邻的网格,即从坐标为(i,j)的网格移向(i-1, j),(i+1, j),(i,j-1),(i,j+1)四个网格,机器人不能走出整个nn的网格。游戏开始时,你可以自由选定机器人的初始位置。现在你知道在一段时间内,鼹鼠出现的时间和地点,希望你编写一个程序使机器人在这一段时间内打死尽可能多的鼹鼠。
输入格式:
第一行为n(n<=1000), m(m<=10000),其中m表示在这一段时间内出现的鼹鼠的个数,接下来的m行每行有三个数据time,x,y表示有一只鼹鼠在游戏开始后time个时刻,在第x行第y个网格里出现了一只鼹鼠。Time按递增的顺序给出。注意同一时刻可能出现多只鼹鼠,但同一时刻同一地点只可能出现一只鼹鼠。
输出格式:
仅包含一个正整数,表示被打死鼹鼠的最大数目
题目看着很长很吓人,其实就是在一个平面内,鼹鼠们会在不同时间、不同位置出现,同一时刻会再不同地点出现鼹鼠,一个地点在某一时刻只会出现一只鼹鼠。机器人从任意地点开始走,一个单位时间走一个单位长度,不可以斜着走。求最多能打死的鼹鼠个数。这道题本质上也是求最大上升子序列,只不过是三维的,不是很好想。
完整代码如下:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define N 1005
#define l 10005
struct stu{
int x,y,t;
}s[l];
int f[N],n,m,i,j,ans;
int dis(int i,int j){
return abs(s[i].x-s[j].x)+abs(s[i].y-s[j].y);
}
int main(){
cin>>n>>m;
for(i=1;i<=m;i++){
scanf("%d%d%d",&s[i].t,&s[i].x,&s[i].y);
f[i]=1;
for(j=1;j<i;j++){
if(s[i].t-s[j].t>=dis(i,j)){
f[i]=max(f[i],f[j]+1);
}
ans=max(ans,f[i]);
}
}
cout<<ans;
return 0;
}
浙公网安备 33010602011771号