动态规划——背包

Wikioi 3729 飞扬的小鸟

题目描述 Description

输入描述 Input Description

输出描述 Output Description

输出文件名为 bird.out。

共两行。

第一行,包含一个整数,如果可以成功完成游戏,则输出 1,否则输出 0。

第二行,包含一个整数,如果第一行为 1,则输出成功完成游戏需要最少点击屏幕数,

否则,输出小鸟最多可以通过多少个管道缝隙。

样例输入 Sample Input

样例输出 Sample Output

【输入输出样例说明】

如下图所示,蓝色直线表示小鸟的飞行轨迹,红色直线表示管道。

数据范围及提示 Data Size & Hint

对于 30%的数据:5≤n≤10,5≤m≤10,k=0,保证存在一组最优解使得同一单位时间最多点击屏幕 3 次;

对于 50%的数据:5≤n≤20,5≤m≤10,保证存在一组最优解使得同一单位时间最多点击屏幕 3 次;

对于 70%的数据:5≤n≤1000,5≤m≤100;

对于 100%的数据: 5≤n≤10000, 5≤m≤1000, 0≤k<n, 0<X<m, 0<Y<m, 0<P<n, 0≤L<H  ≤m,L +1<H。

思路:

难题……,敲了一上午,最高只有70分,最后看了题解才过QAQ

看题就知道是完全背包,但是跟完全背包的一般优化方法又有不同,因为到达一个位置既可以从另外一个位置点击多次,也可以从x-1处点击一次,还要注意如果触顶不会再往上走,还要注意管子上设初值的问题

代码:

①自己敲的70分

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<algorithm>
 6
 7 using namespace std;
 8 const int maxn = 10005,maxnum = 100000;
 9 struct vain{
10     int high;
11     int low;
12 };
13
14 int n,m,k,up[maxn],down[maxn],dp[maxn][maxn],vis[maxn];
15 vain upp[maxn];
16 int main(){
17     cin>>n>>m>>k;
18     for(int i = 0;i < n;i++){
19         cin>>up[i]>>down[i];
20
21     }
22     int p,l,h;
23     for(int i = 1;i <= n+1;i++) {
24         for(int j = 0;j <= m;j++){
25             dp[i][j] = maxnum;
26         }
27         upp[i-1].high = maxn;
28         upp[i-1].low = -maxn;
29     }
30     for(int i = 1;i <= k;i++){
31         cin>>p>>l>>h;
32         upp[p].high = h;
33         upp[p].low = l;
34         vis[p] = 1;
35     }
36     for(int i =  1;i <= n;i++){
37         for(int j = 1;j <= m;j++){
38             if(j!=m){
39             if(j <= upp[i].low) continue;
40             if(j >= upp[i].high) break;
41             if(j - up[i-1] > 0) dp[i][j] = min(dp[i][j],min(dp[i-1][j-up[i-1]]+1,dp[i][j-up[i-1]]+1));
42             if(j + down[i-1] <= m) dp[i][j] = min(dp[i][j],dp[i-1][j+down[i-1]]);
43             }
44             if(j == m){
45                 for(int q = m-up[i-1] ;q <= m;q++) dp[i][j] = min(dp[i][j],min(dp[i-1][q] + 1,dp[i][q] + 1));
46             }
47
48         }
49     }
50     int ans = maxnum,key = 1,sea = n-1,sign,acc = 0;
51     for(int i = 1;i <= m;i++) ans = min(ans,dp[n][i]);
52     if(ans == maxnum) key = 0;
53     if(key) cout<<1<<endl<<ans;
54     else{
55         for(;sea >= 0;sea--){
56             for(int i = 1;i <= m;i++){
57                 if(dp[sea][i] < maxnum) sign = 1;
58             }
59             if(sign) break;
60         }
61         for(int i = 0;i < sea;i++) if(vis[i]) acc++;
62         cout<<0<<endl<<acc;
63     }
64     return 0;
65 }

②照着题解改的满分

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<algorithm>
 6
 7 using namespace std;
 8 const int maxn = 10005,maxnum = 100000;
 9 struct vain{
10     int high;
11     int low;
12 };
13
14 int n,m,k,up[maxn],down[maxn],dp[maxn][1005],vis[maxn];
15 vain upp[maxn];
16 int main(){
17     cin>>n>>m>>k;
18     for(int i = 0;i < n;i++){
19         cin>>up[i]>>down[i];
20
21     }
22     int p,l,h;
23     for(int i = 1;i <= n+1;i++) {
24         for(int j = 0;j <= m;j++){
25             dp[i][j] = maxnum;
26         }
27         upp[i-1].high = m+1;
28         upp[i-1].low = 0;
29     }
30     dp[0][0] = maxnum;
31     int arrive = k;
32     for(int i = 1;i <= k;i++){
33         cin>>p>>l>>h;
34         upp[p].high = h;
35         upp[p].low = l;
36         vis[p] = 1;
37     }
38     for(int i =  1;i <= n;i++){
39         for(int j = 1;j <= m;j++){
40             if(j >= up[i-1]){
41             dp[i][j] = min(dp[i][j],min(dp[i-1][j-up[i-1]]+1,dp[i][j-up[i-1]]+1));
42             }
43             if(j == m){
44                 for(int q = m-up[i-1] ;q <= m;q++) dp[i][j] = min(dp[i][j],min(dp[i-1][q] + 1,dp[i][q] + 1));
45             }
46
47         }
48         for(int j = upp[i].low+1;j < upp[i].high;j++) if(j + down[i-1] <=m) dp[i][j] = min(dp[i][j], dp[i-1][j+down[i-1]]);
49         for(int j = 1;j <= upp[i].low;j++) dp[i][j] = maxnum;
50         for(int j = upp[i].high;j <= m;j++) dp[i][j] = maxnum;
51     }
52     int cnt = k, ans = maxnum;
53     for (int i = n; i >= 1; i--) {
54         for (int j = upp[i].low+1; j <= upp[i].high-1; ++j)
55             if (dp[i][j] < maxnum)
56                ans = min(ans, dp[i][j]);
57         if (ans != maxnum) break;
58         if (upp[i].high <= m)
59            cnt --;
60     }
61     if(cnt==k)
62         printf("1\n%d\n", ans);
63     else
64         printf("0\n%d\n", cnt);
65     return 0;
66 }

③题解(滚动数组)

  1 #include <cmath>
  2
  3 #include <cstdio>
  4
  5 #include <cstring>
  6
  7 #include <cstdlib>
  8
  9 #include <algorithm>
 10
 11
 12
 13 using namespace std;
 14
 15
 16
 17 const int maxn=1e4+10;
 18
 19 const int maxm=1e3+10;
 20
 21 const int INF=0x3f3f3f3f;
 22
 23
 24
 25 int n,m,k,ans;
 26
 27 int x[maxn],y[maxn];
 28
 29 int up[maxn],down[maxn];
 30
 31 int last[maxm],now[maxm];
 32
 33
 34
 35 inline int in(){
 36
 37 int x=0;char ch=getchar();
 38
 39 while(ch>‘9‘ || ch<‘0‘) ch=getchar();
 40
 41 while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
 42
 43 return x;
 44
 45 }
 46
 47
 48
 49 void prework(){
 50
 51 int t;
 52
 53 n=in();m=in();k=in();
 54
 55 for(int i=0;i<n;i++) x[i]=in(),y[i]=in();
 56
 57 for(int i=0;i<=n;i++) up[i]=m+1,down[i]=0;
 58
 59 for(int i=1;i<=k;i++){
 60
 61 t=in();down[t]=in();up[t]=in();
 62
 63 }
 64
 65 }
 66
 67
 68
 69 int Min(int a,int b){
 70
 71 if(a>b) return b;
 72
 73 return a;
 74
 75 }
 76
 77
 78
 79 void mainwork(){
 80
 81 last[0]=INF;
 82
 83 int i,cnt=0;
 84
 85 memset(last,0x3f,sizeof(last));
 86
 87 for(int i=1;i<=m;i++) last[i]=0;
 88
 89 for(i=1;i<=n;i++){
 90
 91 memset(now,0x3f,sizeof(now));
 92
 93 for(int j=x[i-1];j<m;j++)
 94
 95 now[j]=Min(now[j],last[j-x[i-1]]+1),now[j]=Min(now[j],now[j-x[i-1]]+1);
 96
 97 for(int k=m-x[i-1];k<=m;k++)
 98
 99 now[m]=Min(now[m],last[k]+1),now[m]=Min(now[m],now[k]+1);
100
101 for(int j=down[i]+1;j<up[i] && j<=m-y[i-1];j++)
102
103 now[j]=Min(now[j],last[j+y[i-1]]);
104
105 for(int j=down[i]+1;j<up[i];j++) last[j]=now[j];
106
107 for(int j=1;j<=down[i];j++) last[j]=INF;
108
109 for(int j=up[i];j<=m;j++) last[j]=INF;
110
111 ans=INF;
112
113 for(int j=down[i]+1;j<up[i];j++) ans=Min(ans,last[j]);
114
115 if(ans==INF) break;
116
117 if(up[i]<=m) cnt++;
118
119 }
120
121 if(i<=n) printf("0\n%d",cnt);
122
123 else printf("1\n%d",ans);
124
125 }
126
127
128
129 int main(){
130
131 prework();
132
133 mainwork();
134
135 return 0;
136
137 }

时间: 2024-09-29 08:05:37

动态规划——背包的相关文章

Leetcode 494 Target Sum 动态规划 背包+滚动数据

这是一道水题,作为没有货的水货楼主如是说. 题意:已知一个数组nums {a1,a2,a3,.....,an}(其中0<ai <=1000(1<=k<=n, n<=20))和一个数S c1a1c2a2c3a3......cnan = S, 其中ci(1<=i<=n)可以在加号和减号之中任选. 求有多少种{c1,c2,c3,...,cn}的排列能使上述等式成立. 例如: 输入:nums is [1, 1, 1, 1, 1], S is 3. 输出 : 5符合要求5种

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

问题 A: 导弹拦截 时间限制: 1 Sec  内存限制: 128 MB 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意 的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所 有的导弹.输入导弹一次飞来的高度(雷达给出的高度不大于30000的正整数).计算这套系统最多能拦截多少导弹. 输入 n颗依次飞来的导弹高度,导弹颗数<=1

【洛谷】【动态规划/背包】P1833 樱花

[题目描述:] 爱与愁大神后院里种了n棵樱花树,每棵都有美学值Ci.爱与愁大神在每天上学前都会来赏花.爱与愁大神可是生物学霸,他懂得如何欣赏樱花:一种樱花树看一遍过,一种樱花树最多看Ai遍,一种樱花树可以看无数遍.但是看每棵樱花树都有一定的时间Ti.爱与愁大神离去上学的时间只剩下一小会儿了.求解看哪几棵樱花树能使美学值最高且爱与愁大神能准时(或提早)去上学. [输入格式:] 共n+1行: 第1行:三个数:现在时间Ts(几点:几分),去上学的时间Te(几点:几分),爱与愁大神院子里有几棵樱花树n.

动态规划--背包

1. 01背包:有 N 件物品和一个容量为 V 的背包.第 i 件物品的费用是 c[i],价值是 w[i].求解将哪些物品装入背包可使价值总和最大. 对于这类问题我们我们定义f[i][j]表示在前i个物品中选总容量为j所能得到的最大价值为多少于是我们状态转移便是这样 f[i][j]=max(f[i][j],f[i-1][j-w[i]]+v[i]); int f[N][M]; void work() { memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) fo

HDU 1284 钱币兑换问题 (动态规划 背包方案数)

钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 15134    Accepted Submission(s): 9117 Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法.请你编程序计算出共有多少种兑法. Input 每行只有一个正整数N,N小于32768. Outp

金明的预算方案 (背包DP)

累~~~ 题目描述 Description 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子: <dl><dd> <colgroup><col width="66"/> <col

POJ 3211 Washing Clothes 背包题解

本题是背包问题,但是需要转化成背包的. 因为是两个人洗衣服,那么就是说一个人只需要洗一半就可以了,因为不能两个人同时洗一件衣服,所以就成了01背包问题了. 思路: 1 计算洗完同一颜色的衣服需要的总时间totTime 2 利用动态规划背包法求这些衣服能在那些时间点完成 3 求比(totTime+1)/2大的最小时间点 4 得到洗一种颜色衣服的时间,那么继续求下洗一种颜色衣服的时间 5 最后加起来就是答案了. 这个是算法问题. 剩下来就是考编程功力了,因为给出的数据,需要我们自己把衣服分类,分类之

codevs——3111 CYD啃骨头(背包)

裸的01背包 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description CYD吃饭时有N个骨头可以啃,但CYD要午睡了,所以他只有M分钟吃饭,已知啃每个骨头需花费时间Ai,可以得到Bi个单位的营养.问CYD最多得到多少营养. 输入描述 Input Description M  N A1 B1 A2 B2 …… AN BN 输出描述 Output Description 得到的最大营养值 样例输入 Sample Input 10  3

codevs——2841 愤怒的LJF(背包)

样例有误! 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description LJF发现ZPC的积分比他高,他很愤怒. 他挤出T时间做题,他有Q的智慧,他只会做难度系数比他的智慧低或相等的题目. 有N道题,第i道题的时间为Ti,难度系数为Qi,可获积分Wi. LJF有M积分,ZPC有S积分,求LJF最多积分的情况下是否能超过ZPC. 输入描述 Input Description 第一行:N M T Q S 第二行到第N+1行:Ti Qi Wi