[POI2009]Kon

Description
火车沿途有N个车站,告诉你从每一站到每一站的人数,现在查票员只能查K次票,每次查票可以控制目前在车上的所有乘客的车票。求一个查票方案,使得控制的不同的乘客尽量多。 (显然对同一个乘客查票多次是没有意义的,只算一次)

Input
第一行正整数 N K (1≤K<N≤600, K≤50). 接下来N-1行,第i行第j个数描述第i站上,到第i+j站下的乘客个数。总乘客数≤2*10^9

Output
单调增的K个整数,用空格隔开,表示经过哪些站以后查票。

Sample Input
7 2
2 1 8 2 1 0
3 5 1 0 1
3 1 2 2
3 5 6
3 2
1

Sample Output
2 5

本题dp题,设f[i][k]表示到第i个车站检票k次所控制的人数,因为每次检票到下一次检票相当于检查了一个矩阵内的人数,所以可以据此转移。

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())    if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())  x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+'0');
}
const int N=6e2,M=50;
int A[N+10][N+10],sum[N+10][N+10],f[N+10][M+10],pre[N+10][M+10],stack[M+10];
int main(){
    int n=read(),K=read(),Ans=-inf,ID=0;
    for (int i=1;i<n;i++)    for (int j=i+1;j<=n;j++) A[i][j]=read();
    for (int i=1;i<=n;i++)   for (int j=1;j<=n;j++)   sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
    memset(f,128,sizeof(f));
    f[0][0]=0;
    for (int i=1;i<=n;i++){
        for (int k=1;k<=K;k++){
            for (int l=0;l<i;l++){
                int tmp=sum[i][n]-sum[i][i]-sum[l][n]+sum[l][i];
                if (f[i][k]<f[l][k-1]+tmp){
                    f[i][k]=f[l][k-1]+tmp;
                    pre[i][k]=l;
                }
                if (k==K&&Ans<f[i][k]){
                    Ans=f[i][k];
                    ID=i;
                }
            }
        }
    }
    for (int i=ID,k=K;i;i=pre[i][k--])  stack[k]=i;
    for (int i=1;i<=K;i++)   printf("%d",stack[i]),i!=K?putchar(' '):putchar('\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/9118988.html