UVA1336 Fixing the Great Wall 洛谷P2466 [SDOI2008]Sue的小球【区间DP记忆化搜索】
UVA1336 Fixing the Great Wall
Time limit 3000ms
題目大意
長城上有N個地點要修補,給定每個點的位置、初始修復成本,每單位時間增加的成本
給定修補機器人 初始位置及移動速度
求機器人如何移動使得總成本最小
題目分析
將這N個點按位置排序
顯然如果一個點走過他再回頭修一定不會最優
所以任意時刻已修補的區間一定是連續的
即若當前以修好第llllll~rrrrrr個地點,那么下一個修補的一定是ll?1ll-1ll?1或rr+1rr+1rr+1
定義dp[ll][rr][0/1]dp[ll][rr][0/1]dp[ll][rr][0/1]表示已經修好了[ll,rr][ll,rr][ll,rr]區間的地點,且當前所在位置為ll(0)ll(0)ll(0)還是rr(1)rr(1)rr(1)
修補完剩下的地點所需最小化費
初始化dp[1][n][0]=dp[1][n][1]=0dp[1][n][0]=dp[1][n][1]=0dp[1][n][0]=dp[1][n][1]=0,其余為INF
狀態轉移方程
令W=Sum[n]?(Sum[rr]?Sum[ll?1])W=Sum[n]-(Sum[rr]-Sum[ll-1])W=Sum[n]?(Sum[rr]?Sum[ll?1])及計算剩余沒修補的地點每單位時間增加的成本總和
dp[ll][rr][0]=min(dp[ll?1][rr][0]+Len(ll?1,ll)/V?W,dp[ll][rr+1][1]+Len(ll,r+1)/V?W)dp[ll][rr][0]=min(dp[ll-1][rr][0]+Len(ll-1,ll)/V*W,dp[ll][rr+1][1]+Len(ll,r+1)/V*W)dp[ll][rr][0]=min(dp[ll?1][rr][0]+Len(ll?1,ll)/V?W,dp[ll][rr+1][1]+Len(ll,r+1)/V?W)
dp[ll][rr][1]=min(dp[ll?1][rr][0]+Len(ll?1,rr)/V?W,dp[ll][rr+1][1]+Len(rr,r+1)/V?W)dp[ll][rr][1]=min(dp[ll-1][rr][0]+Len(ll-1,rr)/V*W,dp[ll][rr+1][1]+Len(rr,r+1)/V*W)dp[ll][rr][1]=min(dp[ll?1][rr][0]+Len(ll?1,rr)/V?W,dp[ll][rr+1][1]+Len(rr,r+1)/V?W)
注意這里我們還要把機器人的初始位置作為一個點加進去,所以總點數應為N+1
設排序后表示機器人的點為K,從DP(k,k,0)開始記搜即可
答案為dp[k][k][0]+SUMdp[k][k][0]+SUMdp[k][k][0]+SUM (SUM為初始成本總和)
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<algorithm> #include<cstring> using namespace std; typedef double dd;int read() {int f=1,x=0;char ss=getchar();while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return f*x; }const int inf=1e9; const int maxn=1010; int n,v,x; struct node{dd pos,c,dt;}rem[maxn]; bool cmp(node a,node b){return a.pos<b.pos;} dd sum[maxn],dp[maxn][maxn][2];dd DP(int ll,int rr,int d) {if(ll==1&&rr==n+1) return 0;if(dp[ll][rr][d]!=inf) return dp[ll][rr][d];dd resl=0,resr=0,ss=sum[n+1]-(sum[rr]-sum[ll-1]);if(ll>1){if(d==1) resl=(rem[rr].pos-rem[ll-1].pos)/v*ss;else resl=(rem[ll].pos-rem[ll-1].pos)/v*ss;}if(rr<=n){if(d==1) resr=(rem[rr+1].pos-rem[rr].pos)/v*ss;else resr=(rem[rr+1].pos-rem[ll].pos)/v*ss;}if(ll>1) dp[ll][rr][d]=min(dp[ll][rr][d],DP(ll-1,rr,0)+resl);if(rr<=n) dp[ll][rr][d]=min(dp[ll][rr][d],DP(ll,rr+1,1)+resr);return dp[ll][rr][d]; }int main() {while(scanf("%d%d%d",&n,&v,&x)!=EOF){if(n==0&&v==0&&x==0) break; dd ssum=0;for(int i=1;i<=n;++i)scanf("%lf%lf%lf",&rem[i].pos,&rem[i].c,&rem[i].dt);rem[n+1].pos=x; rem[n+1].c=0; rem[n+1].dt=0;//將機器人也作為一個點加入sort(rem+1,rem+2+n,cmp);for(int i=1;i<=n+1;++i)ssum+=rem[i].c,sum[i]=sum[i-1]+rem[i].dt;for(int i=1;i<=n+1;++i)for(int j=1;j<=n+1;++j)dp[i][j][0]=dp[i][j][1]=inf;for(int i=1;i<=n+1;++i)if(rem[i].pos==x){ printf("%.0lf\n",floor(DP(i,i,0)+ssum)); break;}}return 0; }
洛谷P2466 [SDOI2008]Sue的小球
時空限制 1000ms / 128MB
題目描述
Sue和Sandy最近迷上了一個電腦游戲,這個游戲的故事發在美麗神秘并且充滿刺激的大海上,Sue有一支輕便小巧的小船。然而,Sue的目標并不是當一個海盜,而是要收集空中漂浮的彩蛋,Sue有一個秘密武器,只要她將小船劃到一個彩蛋的正下方,然后使用秘密武器便可以在瞬間收集到這個彩蛋。然而,彩蛋有一個魅力值,這個魅力值會隨著彩蛋在空中降落的時間而降低,Sue要想得到更多的分數,必須盡量在魅力值高的時候收集這個彩蛋,而如果一個彩蛋掉入海中,它的魅力值將會變成一個負數,但這并不影響Sue的興趣,因為每一個彩蛋都是不同的,Sue希望收集到所有的彩蛋。
然而Sandy就沒有Sue那么浪漫了,Sandy希望得到盡可能多的分數,為了解決這個問題,他先將這個游戲抽象成了如下模型:
以Sue的初始位置所在水平面作為x軸。
一開始空中有N個彩蛋,對于第i個彩蛋,他的初始位置用整數坐標(xi, yi)表示,游戲開始后,它勻速沿y軸負方向下落,速度為vi單位距離/單位時間。Sue的初始位置為(x0, 0),Sue可以沿x軸的正方向或負方向移動,Sue的移動速度是1單位距離/單位時間,使用秘密武器得到一個彩蛋是瞬間的,得分為當前彩蛋的y坐標的千分之一。
現在,Sue和Sandy請你來幫忙,為了滿足Sue和Sandy各自的目標,你決定在收集到所有彩蛋的基礎上,得到的分數最高。
輸入格式:
第一行為兩個整數N, x0用一個空格分隔,表示彩蛋個數與Sue的初始位置。
第二行為N個整數xi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋的初始橫坐標。
第三行為N個整數yi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋的初始縱坐標。
第四行為N個整數vi,每兩個數用一個空格分隔,第i個數表示第i個彩蛋勻速沿y軸負方向下落的的速度。
輸出格式:
一個實數,保留三位小數,為收集所有彩蛋的基礎上,可以得到最高的分數。
說明
對于30%的數據,N<=20。
對于60%的數據,N<=100。
對于100%的數據,?104<=xi,yi,vi<=104,N<=1000-10^4 <= xi,yi,vi <= 10^4,N < = 1000?104<=xi,yi,vi<=104,N<=1000
題目分析
和上面一樣的題型
每個彩蛋iii的得分看作 初始從坐標yi?y_i-yi??下落距離
為了讓這個得分盡可能的大,轉換一下就是要讓下落距離盡量小
令SUM為初始所有縱坐標總和,sum[i]sum[i]sum[i]記錄viv_ivi?前綴和
dp[ll][rr][0/1]dp[ll][rr][0/1]dp[ll][rr][0/1]表示已經取得了第llllll~rrrrrr的彩蛋且當前在llllll還是rrrrrr,要取完剩下區間能得到的最小下落距離
和上面的轉移如出一轍
記得把初始位置也作為一個點加進去,xixixi升序排序后記搜即可
最后ans=(SUM?DP(K,K,0))/1000ans=(SUM-DP(K,K,0))/1000ans=(SUM?DP(K,K,0))/1000
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<cmath> using namespace std; typedef long long lt; typedef double dd;int read() {int x=0,f=1;char ss=getchar();while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return x*f; }const int inf=1128481603; const int maxn=1010; int n,x0,SUM; struct node{ int xi,yi,vi,f; node(){xi=yi=vi=f=0;}}rem[maxn]; bool cmp(node a,node b){return a.xi<b.xi;} int sum[maxn],dp[maxn][maxn][2];int DP(int ll,int rr,int d) {if(ll==1&&rr==n) return 0;if(dp[ll][rr][d]!=inf) return dp[ll][rr][d];int res=inf,resl=0,resr=0,ss=sum[n]-(sum[rr]-sum[ll-1]);if(ll>1){if(d==1) resl=(rem[rr].xi-rem[ll-1].xi)*ss;else resl=(rem[ll].xi-rem[ll-1].xi)*ss;}if(rr<n){if(d==1) resr=(rem[rr+1].xi-rem[rr].xi)*ss;else resr=(rem[rr+1].xi-rem[ll].xi)*ss; }if(ll>1) res=min(res,resl+DP(ll-1,rr,0));if(rr<n) res=min(res,resr+DP(ll,rr+1,1));return dp[ll][rr][d]=res; }int main() {n=read(); x0=read();for(int i=1;i<=n;++i) rem[i].xi=read();for(int i=1;i<=n;++i) rem[i].yi=read();for(int i=1;i<=n;++i) rem[i].vi=read();rem[++n].xi=x0; rem[n].yi=0; rem[n].vi=0; rem[n].f=1;memset(dp,67,sizeof(dp));sort(rem+1,rem+n+1,cmp);for(int i=1;i<=n;++i) sum[i]=sum[i-1]+rem[i].vi,SUM+=rem[i].yi;for(int i=1;i<=n;++i)if(rem[i].f==1){ printf("%.3lf",(dd)(SUM-DP(i,i,1))/1000.0); break;}return 0; }
總結
以上是生活随笔為你收集整理的UVA1336 Fixing the Great Wall 洛谷P2466 [SDOI2008]Sue的小球【区间DP记忆化搜索】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在html页面中显示JSON数据
- 下一篇: Android EditText软键盘换