动态规划——背包、LIS、LCS

问题 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转移过来。

 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[10005],t[10005],f[10005];
38 int main()
39 {
40     int n=read(),m=read(),j=m;
41     rep(i,1,m) a[i]=read(),t[i]=read(); 
42     per(i,n,1){
43       if (a[j]!=i) f[i]=f[i+1]+1;
44       else
45         while (a[j]==i){
46             f[i]=max(f[i],f[a[j]+t[j]]);
47             j--;
48         }
49     }
50     printf("%d",f[1]);
51 }
View Code

 

问题 F: P1050

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

题目描述

一个字符串A的子串被定义成从A中顺次选出若干个字符构成的串。如A=“cdaad" ,顺次选1,3,5个字符就构成子串" cad" ,现给定两个字符串,求它们的最长共公子串。

输入

第一行两个字符串用空格分开。

输出

最长子串的长度。

样例输入

abccd aecd

样例输出

3

提示

两个串的长度均小于2000

一道LCS裸题飘过~~,

我们可以构造出他的结构特征。f(i,j)表示str1[1]~str1[i]和str2[1]~str2[j]的最长不下降子序列的长度。

然后他的递归式也随之能推出来,f(i,j)=Max(f(i,j-1),f(i-1,j))(str1[i]!=str2[j])||f(i-1,j-1)+1(str1[i]==str2[j]);

 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 2000
38 int f[N][N];
39 int main()
40 {
41     char str1[N],str2[N];
42     scanf("%s%s",str1+1,str2+1);
43     int len1=strlen(str1+1),len2=strlen(str2+1);
44     for (int i=1;i<=len1;i++)
45         for (int j=1;j<=len2;j++)
46             if (str1[i]==str2[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
47             else f[i][j]=max(f[i][j],f[i-1][j]),f[i][j]=max(f[i][j],f[i][j-1]);
48     printf("%d\n",f[len1][len2]);
49     return 0;
50  } 
View Code

问题 G: 运动鞋

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

题目描述

经过几个月的艰苦学习,Iserlohn终于赢得了全额奖学金。作为一个运动鞋狂热爱好者,他决定用所有的钱在运动鞋商店进行消费。 
有一些球鞋Iserlohn要收集,如Air Jordan 和 Nike Pro。而每个品牌已发布各种产品。由于,Iserlohn绝对是一个运动鞋狂热,他意欲购买每个品牌至少有一个产品。 
虽然每个产品的都有相应的定价,但是在Iserlohn心中也有一个价值倾向。由于他的钱有限,他希望最大限度地提高鞋的总价值。显然,作为一个收藏家,他不会购买相同产品的两次。 
现在,Iserlohn需要你帮他找到他的答案,即在至少购买每个品牌的一个产品的情况下,使得所有运动鞋在他心中的总价值最高。 

输入

第1行包含三个整数N,M,K(1<=N<=100,1 <= M<= 10000,1<=K<=10)分别表示共有N种产品,M的钱和K种品牌。 
接下来N行,每行三个整数a,b,c(1<=a<=k, 0<=b,c<100000)分别表示该商品属于哪种品牌,商品标价以及他心目中的价格。 

 

输出

只有一个正整数,输出他心中的最大价值,如果不能满足他的要求,输出“Impossible”

 

样例输入

5 10000 3
1 4 6
2 5 7
3 4 99
1 55 77
2 44 66

样例输出

255

背包题,跟普通的分组背包又有点区别,

我们发现这里需要知道前几组的状态,

f(i,j)表示前i组用了j钱的最大心目价。

如果这个组有值,就从这一维转,

或前一维有值,就从前一维转,

if (dp[i][v-m[i][j]]!=-1)
 dp[i][v]=max(dp[i][v],dp[i][v-m[i][j]]+c[i][j]);
if (dp[i-1][v-m[i][j]]!=-1)
 dp[i][v]=max(dp[i][v],dp[i-1][v-m[i][j]]+c[i][j]);
特别注意:顺序不能换。

因为有几个m值为零的点。

 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 dp[12][12000],num[12],m[12][12000],c[12][12000];
38 int main()
39 {
40     int n,M,k; scanf("%d%d%d",&n,&M,&k);
41     for (int i=1;i<=n;i++){
42         int a,b,C; scanf("%d%d%d",&a,&b,&C);
43         num[a]++; m[a][num[a]]=b; c[a][num[a]]=C; 
44     }
45     memset(dp,-1,sizeof(dp));
46     memset(dp[0],0,sizeof(dp[0]));
47     for (int i=1;i<=k;i++){
48         for (int j=1;j<=num[i];j++){
49             for (int v=M;v>=m[i][j];v--){
50                 if (dp[i][v-m[i][j]]!=-1)
51                     dp[i][v]=max(dp[i][v],dp[i][v-m[i][j]]+c[i][j]);
52                 if (dp[i-1][v-m[i][j]]!=-1)
53                     dp[i][v]=max(dp[i][v],dp[i-1][v-m[i][j]]+c[i][j]);
54             }
55         }
56     }
57     if (dp[k][M]==-1) printf("Impossible\n"); else
58     printf("%d",dp[k][M]);
59     return 0;
60  } 
View Code

 

 

问题 H: 低价购买

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

题目描述

“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。 
这里是某支股票的价格清单: 
日期 1 2 3 4 5 6 7 8 9 10 11 12 
价格 68 69 54 64 68 64 70 67 78 62 98 87 
最优秀的投资者可以购买最多4次股票,可行方案中的一种是: 
日期 2 5 6 10 
价格 69 68 64 62 

 

输入

第1行: N (1 <= N <= 5000),股票发行天数 
第2行: N个数,是每天的股票价格。 

 

输出

仅一行包含两个数:最大购买次数和拥有最大购买次数的方案数(<=231)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这2种方案被认为是相同的。
 

 

样例输入

12
68 69 54 64 68 64 70 67 78 62 98 87

样例输出

4 2
这题是LCS的拓展版,
还要求出方案数,g[i]表示达到f[i]的方案数,
g[i]是前面所有能转移过来的值相加产生。
因为g[i]的存在,所以此题nlgn的优化无法实现。
 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 f[6000],g[6000],a[6000];
38 int main()
39 {
40     int n=read(),nu=0,ans=0;
41     for (int i=1;i<=n;i++) a[i]=read();
42     for (int i=1;i<=n;i++) {
43         f[i]=1;
44         for (int j=1;j<i;j++)
45             if (a[j]>a[i]) f[i]=max(f[i],f[j]+1);
46         if (f[i]==1) g[i]=1;
47         for (int j=1;j<i;j++)
48             if (f[j]+1==f[i] && a[i]<a[j]) g[i]+=g[j];
49             else if(a[j]==a[i] && f[i]==f[j]) g[j]=0;
50         nu=max(f[i],nu);
51     }
52     printf("%d ",nu); 
53     for (int i=1;i<=n;i++)
54         if (f[i]==nu) ans+=g[i];
55     printf("%d\n",ans);
56     return 0;
57  } 
View Code

问题 I: 胖男孩

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

题目描述

麦克正如我们所知的已快乐地结婚,在上个月他胖了70磅。因为手指上的脂肪过多,使他连给他最亲密的朋友斯拉夫克写一个电子邮件都很困难。 
每晚麦克都详细地描述那一天他所吃的所有东西,但有时当他只想按一次某键时往往会按了不止一次,并且他的胖手指还会碰到他不想要按的键,麦克也知道自己的手指有问题,因此他在打字的时候很小心,以确保每打一个想要的字符时误打的字符不超过3个,误打的字符可能在正确字符之前也可能在其之后。 
当斯拉夫克多次收到读不懂的电子邮件后,他总是要求麦克将电子邮件发3遍,使他容易读懂一点。 
编写程序,帮助斯拉夫克根据他所收到的三封电子邮件求出麦克可能写出的最长的信。 

 

输入

输入文件包含了三行文本。每一行文本包括麦克信件的一种版本。其中所有的字符都由英文字母表中的小写字母组成并且不超过100个。 

 

输出

输出文件中第一行即唯一的一行数据应该包含斯拉夫克根据所收到的电子邮件推测出的最长信件。输出其长度

 

样例输入

cecqbhvaiaedpibaluk
cabegviapcihlaaugck
adceevfdadaepcialaukd

样例输出

9

提示

 

{cevapiluk}

这道题有很强的误导性,题中“因此他在打字的时候很小心,以确保每打一个想要的字符时误打的字符不超过3个,误打的字符可能在正确字符之前也可能在其之后。 ”

这句话是句废话,因为管它怎么误打的,LCS总是满足上述条件(最长的信),所以这不是充要条件。

然后就是3维的LCS。

f[i][j][k]表示到第i,j,k三个位置的LCS。

f[i][j][k]=max(f[i-1][j][k],f[i][j-1][k],f[i][j][k-1])(!str1[i]=str2[j]=str3[k])|f[i-1][j-1][k-1](str1[i]=str2[j]=str3[k]);

 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 dp[105][105][105];
38 int main()
39 {
40     char ch1[105],ch2[105],ch3[105];
41     scanf("%s%s%s",ch1+1,ch2+1,ch3+1);
42     int len1=strlen(ch1+1),len2=strlen(ch2+1),len3=strlen(ch3+1);
43     dp[0][0][0]=0;
44     for (int i=1;i<=len1;i++)
45         for (int j=1;j<=len2;j++)
46             for (int k=1;k<=len3;k++)
47                 if (ch1[i]==ch2[j] && ch2[j]==ch3[k]) dp[i][j][k]=dp[i-1][j-1][k-1]+1;
48                 else dp[i][j][k]=max(max(dp[i-1][j][k],dp[i][j-1][k]),dp[i][j][k-1]);
49     printf("%d\n",dp[len1][len2][len3]);
50     return 0;
51  } 
View Code

————————————————————————————终于end了。

posted @ 2017-05-18 21:23  SXia  阅读(619)  评论(0编辑  收藏  举报