[POI2009]KON-Ticket Inspector(二维前缀和+DP)

题意

有n个车站,现在有一辆火车从1到n驶过,给出aij代表从i站上车j站下车的人的个数。列车行驶过程中你有K次检票机会,所有当前在车上的人会被检票,问最多能检多少个不同的人的票

(n<=600,k<=50)

题解

一开始没啥思路,然后瞄了一眼题解。看到了前缀和然后就想前缀和的意义。

结果又没什么收获。绝望之际想到我瞄的那一眼,看到矩阵是倒着的,然后就有了思路。

DP也就轻而易举地想出来了。

我们建立以左上为原点的前缀和。

然后sum[i][i+1]表示的就是经过i号站点的人数。

然后dp[i][j]代表前i个车站以第i个车站为第j个选择的车站的最优解。

方程:

dp[i][j]=max(dp[i][j],dp[x][j-1]+sum[i][i+1]-sum[x][i+1])(0<=x<i)

然后记录dp[i][j]从哪里转移就可以得到答案了。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=700;
 8 int n,k,a[N][N],sum[N][N],dp[N][60],ans,num,ans1,ans2[70],from[N][60];
 9 int main(){
10     scanf("%d%d",&n,&k);
11     num=k;
12     for(int i=1;i<=n;i++){
13         for(int j=1;j<=n-i;j++){
14             scanf("%d",&a[i][j+i]);
15         }
16     }
17 //    for(int i=1;i<=n;i++){
18 //        for(int j=1;j<=n;j++){
19 //            cout<<a[i][j]<<" ";
20 //        }
21 //        cout<<endl;
22 //    }
23     for(int i=1;i<=n;i++){
24         for(int j=n;j>=1;j--){
25             sum[i][j]=sum[i-1][j]+sum[i][j+1]-sum[i-1][j+1]+a[i][j];
26         }
27     }
28 //    for(int i=1;i<=n;i++){
29 //        for(int j=1;j<=n;j++){
30 //            cout<<sum[i][j]<<" ";
31 //        }
32 //        cout<<endl;
33 //    }
34     for(int i=0;i<=n;i++)
35         for(int j=0;j<=k;j++){
36             dp[i][j]=-99999999;
37         }
38     dp[0][0]=0;
39     for(int i=1;i<=n;i++)
40         for(int j=1;j<=min(i,k);j++)
41             for(int x=0;x<i;x++){
42                 if(dp[i][j]<dp[x][j-1]+sum[i][i+1]-sum[x][i+1]){
43                     dp[i][j]=dp[x][j-1]+sum[i][i+1]-sum[x][i+1];
44                     from[i][j]=x;
45                 }
46             }
47     for(int i=k;i<=n-1;i++){
48         if(ans<dp[i][k]){
49             ans1=i;
50             ans=dp[i][k];
51         }
52     }
53 //    cout<<ans<<endl;
54     while(ans1){
55         ans2[num]=ans1;
56         ans1=from[ans1][num];
57         num--; 
58     }
59     for(int i=1;i<=k;i++){
60         printf("%d ",ans2[i]);
61     }
62     return 0;
63 }
View Code

 

posted @ 2018-08-06 20:19  Xu-daxia  阅读(255)  评论(0编辑  收藏  举报