Summary
給出N(N<=1000)個需要繪制的平行于X軸的線段,知道其坐標,以(Y,X1,X2)表示。有一繪圖儀,從Y=0位置開始繪制這些線段。對于同一個Y,繪圖儀可以從X=x1到X=x2,平移時耗費時間|x2-x1|,繪制線段則耗費雙倍時間2|x2-x1|。但是,在垂直方向上,繪圖儀只能從y1移動到y2,y1<y2,且此時X必須=0。線段的繪制必須是完整的,不能只繪制一半?,F問:繪圖儀在規定的之間T內最多能繪制多少條線段。
Solution
使用動態規劃可以解決這個問題。
設DP狀態為:dp[i][j],表示繪制到第i個線段(這個線段必須繪制),繪制了j個線段,所需要的最少時間。那么dp[i][j] = min(dp[k][j-1] + dis(segment[i], segment[k]) + time to draw segment[i]。dis表示兩個線段的“距離”,分情況討論計算即可。
最后統計所有時間小于等于T的方案取出最優的即可。
注意靈活選擇狀態,用范圍小的作為狀態量,將范圍大的選作為狀態值
1
# include <iostream>
2
# include <cstring>
3
# include <cstdio>
4
# include <algorithm>
5
using namespace std;
6
struct node
7

{
8
int y,x1,x2;
9
}data[1005];
10
bool cmp(const node &a,const node &b)
11

{
12
if(a.y!=b.y) return a.y<b.y;
13
else return a.x1<b.x1;
14
}
15
int dp[1005][1005];
16
int main()
17

{
18
int n,t;
19
while(true)
20
{
21
scanf("%d%d",&n,&t);
22
if(!n&&!t) break;
23
for(int i=0;i<n;i++)
24
{
25
scanf("%d%d%d",&data[i].y,&data[i].x1,&data[i].x2);
26
if(data[i].x1>data[i].x2) swap(data[i].x1,data[i].x2);
27
}
28
sort(data,data+n,cmp);
29
int res=0;
30
memset(dp[0],0,sizeof(dp[0]));
31
for(int i=0;i<n;i++)
32
{
33
dp[1][i]=(data[i].x2-data[i].x1)*3+data[i].x1*2;
34
if(dp[1][i]-data[i].x2<=t)
35
res=1;
36
}
37
for(int i=1;i<n;i++)
38
{
39
for(int j=2;j<=i+1;j++)
40
{
41
dp[j][i]=0xfffffff;
42
for(int k=j-2;k<i;k++)
43
dp[j][i]=min(dp[j][i],dp[j-1][k]+(data[k].y==data[i].y?(data[i].x1-data[k].x2)*2+(data[i].x2-data[i].x1)*3:data[i].x1*2+3*(data[i].x2-data[i].x1)));
44
if(dp[j][i]-data[i].x2<=t)
45
res=max(res,j);
46
}
47
}
48
printf("%d\n",res);
49
}
50
return 0;
51
}
52