zoukankan      html  css  js  c++  java
  • [洛谷P3486]POI2009 KON-Ticket Inspector

    问题描述

    Byteasar works as a ticket inspector in a Byteotian National Railways (BNR) express train that connects Byteburg with Bitwise.

    The third stage of the BNR reform (The never ending saga of BNR reforms and the Bitwise hub was presented in the problems Railway from the third stage of XIV Polish OI and Station from the third stage of XV Polish OI. Their knowledge, however, is not required at all in order to solve this problem.) has begun. In particular, the salaries system has already been changed.

    For example, to encourage Byteasar and other ticket inspectors to efficient work, their salaries now depend on the number of tickets (passengers) they inspect. Byteasar is able to control all the passengers on the train in the time between two successive stations, but he is not eager to waste his energy in doing so. Eventually he decided he would check the tickets exactly times per ride.

    Before setting out, Byteasar is given a detailed summary from which he knows exactly how many passengers will travel from each station to another. Based on that he would like to choose the moments of control in such a way that the number of passengers checked is maximal. Obviously, Byteasar is not paid extra for checking someone multiple times - that would be pointless, and would only disturb the passengers. Write a programme that will determine for Byteasar when he should check the tickets in order to maximise his revenue.

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

    传送门

    题面

    题解

    由定义就可以得出状态的表达方式:设(f[i][j])表示在第j个车站时检第i次票的最大检票人数,那么显然(f[i][j])由前面某一个(f[i-1][k])转移过来。那么需要确定的是从k到j有多少人在此时间段上车且没有下车。输入中的矩阵是锯齿形的,实际上全部向右边掉落后可以转化为一个矩阵a,其中(a[i][j])表示在i上车j下车的人数。那么如何找到在一个区间内上车的人数呢?可以发现,在i时还在的人数就是所有在i之前到、在i之后走的人。那么对应的就是矩阵a中满足横坐标不大于i、纵坐标大于i的点的权值和。可以用类似前缀和的方法来计算。扩展到区间,一个时间段(i,j)中在i之后下车且在j之前没有下车的人就是横坐标大于i小于j、纵坐标大于j的点的和。所以,设(sum[i][j])表示以(x,y)为左下角、(1,n)为右下角的矩阵和,则状态转移方程如下:

    [f[i][j]=Max(f[i-1][k]+sum[j][j+1]-sum[k][j+1])_{k=1...j} ]

    答案为:

    [ans=Max(f[m][i])_{i=1...n} ]

    接下来的问题是如何输出路径。记(pre[i][j])表示状态(f[i][j])是从哪一个车站转移过来的,在确定答案后倒推回去即为最佳方案(记得倒序输出)。

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #define N 1002
    using namespace std;
    int n,m,i,j,k,a[N][N],f[N][N],sum[N][N],pre[N][N];
    vector<int> v;
    int main()
    {
    	cin>>n>>m;
    	for(i=1;i<=n;i++){
    		for(j=i+1;j<=n;j++) cin>>a[i][j];
    	}
    	for(i=1;i<=n;i++){
    		for(j=n;j>=1;j--) sum[i][j]=sum[i-1][j]+sum[i][j+1]-sum[i-1][j+1]+a[i][j];
    	}
    	for(i=1;i<=m;i++){
    		for(j=1;j<=n;j++){
    			for(k=i-1;k<j;k++){
    				if(f[i-1][k]+sum[j][j+1]-sum[k][j+1]>f[i][j]){
    					f[i][j]=f[i-1][k]+sum[j][j+1]-sum[k][j+1];
    					pre[i][j]=k;
    				}
    			}
    		}
    	}
    	int maxx=0,ans=0;
    	for(i=m;i<=n;i++){
    		if(f[m][i]>maxx){
    			maxx=f[m][i];
    			ans=i;
    		}
    	}
    	int p=ans;
    	for(i=m;i>=1;i--){
    		v.push_back(p);
    		p=pre[i][p];
    	}
    	for(i=v.size()-1;i>=0;i--) cout<<v[i]<<' ';
    	cout<<endl;
    	return 0;
    }
    
  • 相关阅读:
    C#计算两个时间年份月份天数(根据生日计算年龄)差,求时间间隔
    C#四舍五入保留一位小数
    给Editplus去掉.bak文件
    $().each() 与 $.each()解析
    VS 2013+Qt 5.4.1
    HDU 5228 ZCC loves straight flush( BestCoder Round #41)
    产品经理的修炼:如何把梳子卖给和尚
    c++ STL unique , unique_copy函数
    linux定时备份mysql数据库文件
    Python——异常基础
  • 原文地址:https://www.cnblogs.com/LSlzf/p/10703322.html
Copyright © 2011-2022 走看看