动态规划——背包LISLCS

Posted SummerSky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——背包LISLCS相关的知识,希望对你有一定的参考价值。

问题 A: 导弹拦截

时间限制: 1 Sec  内存限制: 128 MB

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意 的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所 有的导弹。
输入导弹一次飞来的高度(雷达给出的高度不大于30000的正整数)。计算这套系统最多能拦截多少导弹。

输入

n颗依次飞来的导弹高度,导弹颗数<=1000。

输出

一套系统最多拦截的导弹数。

样例输入

7
300 250 275 252 200 138 245

样例输出

5

这题是一道裸的LIS,

f(n)表示1~n内最多拦截的导弹数。

有:f(n)=Max(f(i)+1)(i<n && a[i]>=a[j])

f值相等的我们只用保留a值最小的,再二分查找即可。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=\' \',ch=getchar();
33 while(ch<\'0\' || ch>\'9\')last=ch,ch=getchar();
34 while(ch>=\'0\' && ch<=\'9\')ans=ans*10+ch-\'0\',ch=getchar();
35 if(last==\'-\')ans=-ans; return ans;
36 }
37 int a[10000],b[10000];
38 const int oo=1e+08;
39 int find (int l,int r,int val){
40     while (l<r){
41         int mid=(l+r)>>1;
42         if (b[mid]<val) r=mid;
43         else l=mid+1;
44     }
45     return r;
46 }
47 int main()
48 {
49     int n=read(),nu=0;
50     for (int i=1;i<=n;i++) a[i]=read();
51     for (int i=1;i<=n;i++){
52         int j=find(1,nu+1,a[i]);
53         if (nu+1==j) b[++nu]=a[i];
54         else b[j]=a[i];
55     }
56     printf("%d",nu);
57     return 0;
58  }
View Code

 

问题 B: 友好城市

时间限制: 1 Sec  内存限制: 128 MB

题目描述

Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置不同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。
每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府作出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。

输入

第1行,一个整数N(1<=N<=50000,表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的左边。(0<=xi<=10000)

输出

仅一行,输出一个整数,政府所能批准的最多申请书。

样例输入

7
22 4
2 6
10 3
15 12
9 8
17 17
4 2

样例输出

4

题目中说不能相交,所以可以先将一维排序,在比较另一维,

然后我们就见到了熟悉的东西——LIS.

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=\' \',ch=getchar();
33 while(ch<\'0\' || ch>\'9\')last=ch,ch=getchar();
34 while(ch>=\'0\' && ch<=\'9\')ans=ans*10+ch-\'0\',ch=getchar();
35 if(last==\'-\')ans=-ans; return ans;
36 }
37 #define N 50005
38 int b[N];
39 struct node
40 {
41     int x,y;
42 }a[N];
43 bool cmp(node a,node b){
44     return a.x<b.x||a.x==b.x&&b.x<b.y;
45 }
46 const int oo=1e+08;
47 int find(int l,int r,int val){
48     b[r]=oo;
49     while (l<r){
50         int mid=(l+r)>>1;
51         if (b[mid]>val) r=mid;
52         else l=mid+1;
53     }
54     return r;
55 }
56 int main()
57 {
58     int n=read(),nu=0;
59     for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
60     sort(a+1,a+n+1,cmp);
61     for (int i=1;i<=n;i++){
62         int j=find(1,nu+1,a[i].y);
63         if (nu+1==j) b[++nu]=a[i].y;
64         else b[j]=a[i].y;
65     }
66     printf("%d\\n",nu);
67     return 0;
68  } 
View Code

 

问题 C: 0/1背包

时间限制: 1 Sec  内存限制: 128 MB

题目描述

一个旅行者有一个最多能装m公斤物品的背包,现在有n件物品,它们的重量分别是w1,w2,…,wn,它们的价值分别为c1,c2,…,cn。若每件物品只有一件,求旅行者能获得的最大总价值。

输入

第一行:两个整数,m(背包容量,m<=200)和n(物品数量,n<=30)。
第二~n+1行:每行两个整数wi,ci,表示每个物品的重量和价值。

输出


一个数据,表示最大总价值。

样例输入

10 4
2 1
3 3
4 5
7 9

样例输出

12

只是最初始的背包问题。

f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。 

f[i][v]=max(f[i-1][v],f[i-1][v-Ci]+Wi);

而每次主循环中以v的递减顺序计算 f[v],这样才

能保证计算f[v]时f[v-Ci]保存的是状态f[i-1][v-Ci]的值。

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=\' \',ch=getchar();
33 while(ch<\'0\' || ch>\'9\')last=ch,ch=getchar();
34 while(ch>=\'0\' && ch<=\'9\')ans=ans*10+ch-\'0\',ch=getchar();
35 if(last==\'-\')ans=-ans; return ans;
36 }
37 #define N 300
38 int w[N],c[N],f[N];
39 int main()
40 {
41     int m=read(),n=read(),Max=0;
42     for (int i=1;i<=n;i++) w[i]=read(),c[i]=read();
43     for (int i=1;i<=n;i++)
44         for (int j=m;j>=w[i];j--)
45             f[j]=max(f[j],f[j-w[i]]+c[i]),Max=max(Max,f[j]);
46     printf("%d\\n",Max);
47     return 0;
48  } 
View Code

 

问题 D: P1013

时间限制: 1 Sec  内存限制: 128 MB

题目描述

" 找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见." " 诶,别再见啊..." 七夕...七夕...七夕这个日子,对于sqybi这种单身的菜鸟来说是多么的痛苦...虽然他听着这首叫做" 找啊找啊找GF" 的歌,他还是很痛苦.为了避免这种痛苦,sqybi决定要给自己找点事情干.他去找到了七夕模拟赛的负责人zmc  MM,让她给自己一个出题的任务.经过几天的死缠烂打,zmc  MM终于同意了. 但是,拿到这个任务的sqybi发现,原来出题比单身更让人感到无聊-_-....所以,他决定了,要在出题的同时去办另一件能够使自己不无聊的事情--给自己找GF. sqybi现在看中了n个MM,我们不妨把她们编号1到n.请MM吃饭是要花钱的,我们假设请i号MM吃饭要花rmb[i]块大洋.而希望骗MM当自己GF是要费人品的,我们假设请第i号MM吃饭试图让她当自己GF的行为(不妨称作泡该MM)要耗费rp[i]的人品.而对于每一个MM来说,sqybi都有一个对应的搞定她的时间,对于第i个MM来说叫做time[i].  sqybi保证自己有足够的魅力用time[i]的时间搞定第i个MM^_^. sqybi希望搞到尽量多的MM当自己的GF,这点是毋庸置疑的.但他不希望为此花费太多的时间(毕竟七夕赛的题目还没出),所以他希望在保证搞到MM数量最多的情况下花费的总时间最少. sqybi现在有m块大洋,他也通过一段时间的努力攒到了r的人品(这次为模拟赛出题也攒rp哦~~).他凭借这些大洋和人品可以泡到一些MM.他想知道,自己泡到最多的MM花费的最少时间是多少. 注意sqybi在一个时刻只能去泡一个MM--如果同时泡两个或以上的MM的话,她们会打起来的...

输入

输入的第一行是n,表示sqybi看中的MM数量.接下来有n行,依次表示编号为1,  2,  3,  ...,  n的一个MM的信息.每行表示一个MM的信息,有三个整数:rmb,  rp和time.最后一行有两个整数,分别为m和r.

输出

你只需要输出一行,其中有一个整数,表示sqybi在保证MM数量的情况下花费的最少总时间是多少.

样例输入

4
1 2 5
2 1 6
2 2 2
2 2 3
5 5

样例输出

13

提示

 

数据规模 对于20%数据,1< =n< =10; 对于100%数据,1< =rmb< =100,1< =rp< =100,1< =time< =1000; 对于100%数据,1< =m< =100,1< =r< =100,1< =n< =100. Hint sqybi说:如果题目里说的都是真的就好了... sqybi还说,如果他没有能力泡到任何一个MM,那么他就不消耗时间了(也就是消耗的时间为0),他要用这些时间出七夕比赛的题来攒rp... 出题人 sqybi  GG

用背包的基本做法,f[i][j]表示用了i的钱,j的rp最多能泡到的MM数。

g[i][j]表示能泡到最多数量的最小代价。

转移:

if (f[j][k]==f[j-w[i]][k-r[i]]+1) t[j][k]=min(t[j][k],t[j-w[i]][k-r[i]]+c[i]);
else if (f[j][k]<f[j-w[i]][k-r[i]]+1) f[j][k]=f[j-w[i]][k-r[i]]+1,t[j][k]=t[j-w[i]][k-r[i]]+c[i];
 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=\' \',ch=getchar();
33 while(ch<\'0\' || ch>\'9\')last=ch,ch=getchar();
34 while(ch>=\'0\' && ch<=\'9\')ans=ans*10+ch-\'0\',ch=getchar();
35 if(last==\'-\')ans=-ans; return ans;
36 }
37 const int oo=1e+08;
38 #define N 1000
39 int f[N][N],t[N][N],w[N],r[N],c[N];
40 int main()
41 {
42     int n=read();
43     for (int i=1;i<=n;i++) w[i]=read(),r[i]=read(),c[i]=read();
44     int M=read(),R=read();
45     for (int i=1;i<=n;i++)
46         for (int j=M;j>=w[i];j--)
47             for (int k=R;k>=r[i];k--){
48                 if (f[j][k]==f[j-w[i]][k-r[i]]+1) t[j][k]=min(t[j][k],t[j-w[i]][k-r[i]]+c[i]);
49                 else if (f[j][k]<f[j-w[i]][k-r[i]]+1) f[j][k]=f[j-w[i]][k-r[i]]+1,t[j][k]=t[j-w[i]][k-r[i]]+c[i];
50             }
51     printf("%d\\n",t[M][R]);
52     return 0;
53  } 
View Code

问题 E: P1034

时间限制: 1 Sec  内存限制: 128 MB

题目描述

尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。 尼克的一个工作日为N分钟,从第一分钟开始到第N分钟结束。当尼克到达单位后他就开始干活。如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去写成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第P分钟开始,持续时间为T分钟,则该任务将在第P+T-1分钟结束。 写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。

输入

输入数据第一行包含两个用空格隔开的整数N和K,1≤N≤10000,1≤K≤10000,N表示尼克的工作时间,单位为分,K表示任务总数。 接下来共有K行,每一行有两个用空格隔开的整数P和T,表示该任务从第P分钟开始,持续时间为T分钟,其中1≤P≤N,1≤P+T-1≤N。

输出

输出文件仅一行包含一个整数表示尼克可能获得的最大空暇时间。

样例输入

15 6
1 2
1 6
4 11
8 5
8 1
11 5

样例输出

4

提示

 某ACM经典题

这道题如果顺推的话很容易发现不知道前面的是否用做。

我们就想到了逆推,f[i]表示i~n的空闲时间,

如果当前位置有任务的话就从后面转移过来,

否则就后面一位加1转移过来。