poj 1991 Turning in Homework(贪心+区间dp)
题目链接:poj 1991 Turning in Homework
题意:
Bessie要交作业,现在知道每个教师的位置,假设都位于X轴上,每份作业都有一个最早交的时间,知道公交车站位于坐标B的对面,假设他每走一个单位耗费时间是1,求他交完作业到达公交车站那最少的时间是什么?
题解:
思想比较好,下面题解来自网上:
贪心:当有一段连续区间[i,j]未交时,取i或j是最优的。
贪心思想证明:如果在[i,j]这段连续区间都没有被取的时候取了中间的m,那么后来一定要从m返回到i或者j,这时候是一定走了“冤枉路的”。而如果这时取了i或者j,那么到中间的时候m一定可以取。证毕。
区间DP:
dp[i][j][0]表示为i-j区间尚未完成交作业的最少时间,其中0代表只交了i作业,dp[i][j][1]同理就是只交了j作业,那么我们将很容易想出来,这是由大区间逐渐推出小区间的一个过程,最终的dp[i][i][0]和dp[i][i][1]就代表停留在i位置的最少时间,最后再加上i-B的距离就是到达公交车站的时间
状态转移方程有四个
dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+c[i].x-c[i-1].x);
dp[i][j][0]=min(dp[i][j][0],dp[i][j+1][1]+c[j+1].x-c[i].x);
dp[i][j][1]=min(dp[i]j][1],dp[i-1][j][0]+c[j].x-c[i-1].x);
dp[i][j][1]=min(dp[i][j][1],dp[i][j+1][1]+c[j+1].x-c[j].x);
每次还有和时间比较下,有可能走到那个点了,却还不够最早交作业的时间。
1 #include<cstdio> 2 #include<algorithm> 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4 using namespace std; 5 typedef pair<int,int>P; 6 7 const int N=1007,inf=1e9+7; 8 9 int n,h,b,dp[N][N][2]; 10 P a[N]; 11 12 void up(int &a,int b){if(a>b)a=b;} 13 14 int main(){ 15 while(~scanf("%d%d%d",&n,&h,&b)) 16 { 17 F(i,0,n+1)F(j,0,n+1)dp[i][j][0]=dp[i][j][1]=inf; 18 F(i,1,n)scanf("%d%d",&a[i].first,&a[i].second); 19 sort(a+1,a+1+n); 20 dp[1][n][0]=max(a[1].first,a[1].second); 21 dp[1][n][1]=max(a[n].first,a[n].second); 22 F(i,1,n)for(int j=n;j>=i;j--) 23 { 24 up(dp[i][j][0],max(dp[i-1][j][0]+a[i].first-a[i-1].first,a[i].second)); 25 up(dp[i][j][0],max(dp[i][j+1][1]+a[j+1].first-a[i].first,a[i].second)); 26 up(dp[i][j][1],max(dp[i-1][j][0]+a[j].first-a[i-1].first,a[j].second)); 27 up(dp[i][j][1],max(dp[i][j+1][1]+a[j+1].first-a[j].first,a[j].second)); 28 } 29 int ans=inf; 30 F(i,1,n)up(ans,min(dp[i][i][0],dp[i][i][1])+abs(a[i].first-b)); 31 printf("%d\n",ans); 32 } 33 return 0; 34 }