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