题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3469
很好的区间DP
思路:
我们可以自己在本子上画一个x轴模拟一下过程,然后我们会发现对于一个区间(l,r),一旦我们访问完了l和r,那么对于整个由(l,r)组成的区间,我们一定也已经访问过了
所以我们可以定义dp[l][r][0]表示访问完区间[i,j]并留在左端点,dp[i][j][1]表示访问完区间[i,j]并留在右端点。
那么我们就比较容易的出状态转移方程:
dp[i][j][0] 可以根据dp[i+1][j][0]和dp[i+1][j][1]得到。
dp[i][j][1] 可以根据dp[i][j-1][0]和dp[i][j-1][1]得到。
具体请参考我的代码
代码:

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int MAXN=1010; 7 const int INF=0x3f3f3f3f; 8 class person 9 { 10 public: 11 int x; 12 int w; 13 }; 14 person man[MAXN]; 15 int dp[MAXN][MAXN][2]; 16 bool cmp(person a,person b) 17 { 18 return a.x<b.x; 19 } 20 int sum[MAXN]; 21 22 int main() 23 { 24 int n,v,x; 25 while(scanf("%d%d%d",&n,&v,&x)==3) 26 { 27 for(int i=1;i<=n;i++) 28 { 29 scanf("%d%d",&man[i].x,&man[i].w); 30 } 31 n++; 32 man[n].x=x; 33 man[n].w=0; 34 sort(man+1,man+n+1,cmp); 35 sum[0]=0; 36 for(int i=1;i<=n;i++) 37 sum[i]=sum[i-1]+man[i].w; 38 int start; 39 for(int i=1;i<=n;i++) 40 if(man[i].x==x) 41 { 42 start=i; 43 break; 44 } 45 for(int i=1;i<=n;i++) 46 for(int j=1;j<=n;j++) 47 dp[i][j][0]=dp[i][j][1]=INF; 48 dp[start][start][0]=dp[start][start][1]=0; 49 for(int i=start;i>=1;i--) 50 for(int j=start;j<=n;j++) 51 { 52 if(i==j)continue; 53 dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(sum[i]+sum[n]-sum[j])*(man[i+1].x-man[i].x)); 54 dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(sum[i]+sum[n]-sum[j])*(man[j].x-man[i].x)); 55 56 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(sum[i-1]+sum[n]-sum[j-1])*(man[j].x-man[i].x)); 57 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(sum[i-1]+sum[n]-sum[j-1])*(man[j].x-man[j-1].x)); 58 } 59 cout<<v*min(dp[1][n][0],dp[1][n][1])<<endl;//important 60 } 61 return 0; 62 }