zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    弱网测试(分析篇)
    弱网测试(资料罗列篇)
    2018年上半年系统分析师上午试题答案
    2018年上半年系统分析师案例分析答案
    测试执行过程注意事项
    略看操作系统
    Activity生命周期
    Android中的数据存储
    Android 进程生命周期 Process Lifecycle
    Android学习链接大放送
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9432667.html
Copyright © 2011-2022 走看看