【纪中OJ】登机

不想你离开。 提交于 2020-02-04 02:45:00

早知道早点敲博赚访问量
Description
小H是机场登机的执行经理。他的工作是优化登机流程。飞机上的座位有S行,编号从1到s,每行有六个座位,标记为A到F。
在这里插入图片描述
今天 有n个乘客陆续登机,第i名乘客的座位在第Ri行,则第i名乘客的登机难度等于在他登机时坐在1…R(i-1)行的乘客的人数。
例如,如果有10名乘客,他们的座位是6A,4B,2E,5F,2A,3F,1C,10E,8B,5A,那么他们的登机困难分别是0,0,0,2,0,2,0,7,7,5,则难度总和为23 。
为了降低登机难度,小H想要将飞机座位划分为k个区域。每一个区域必须是连续的行。划分成k个区域之后,乘客的登机顺序不会改变,但是每个乘客的登机难度将只统计该乘客所在区域前面乘客的人数。
例如,在上面的例子中,如果我们把该平面分成两个区域: 5-10行和1-4行 ,然后在第一区域中的乘客的座位为6A,5F,10E,8B,5A;在第二区域中的乘客的座位为4B,2E,2A,3F,1C,这种情况下,登机难度综合为6。
现在,小H不知道该怎么划分这k个区域,才能让乘客的登机难度总和最少。

Input
输入文件第一行包含三个整数N,S,和k,下一行包含n个整数(1≤Ri≤S),输入保证每一行座位由最多有6名乘客。

Output
输出文件包含一个整数,表示登机可能的最小登机难度。

Sample Input
10 12 2
6 4 2 5 2 3 1 11 8 5

Sample Output
6

Data Constraint
40%的数据,n<=100,s<=100
100%的数据,n<=1000,s<=1000, k<=50, k<=s

这数据范围一看就知道是DP……

变量解释👇
p[i][j] 前j行给第i行带来的总登机难度
f[i][j] 若i~j为一个机舱,这个机舱的难度
dp[i][j] 将前i行划分为j个机舱

#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int n,s,k,r[100001],p[1001][1001],f[1001][1001],dp[1001][1001];
int main(){
	freopen("board.in","r",stdin);
	freopen("board.out","w",stdout);
	memset(dp,INF,sizeof(dp));
    scanf("%d%d%d",&n,&s,&k);
    for(int i=1;i<=n;i++){
    	scanf("%d",&r[i]);
    	for(int j=1;j<i;j++) if(r[j]<r[i]) p[r[i]][r[j]]++;//如果j的位置比i前,j对i造成的难度+1
	}
	for(int i=1;i<=s;i++){
		for(int j=1;j<=s;j++){
			p[i][j]+=p[i][j-1];//前i行给第j行带来的总登机难度。
		}
	}	
	for(int i=1;i<=s;i++){
		for(int j=1;j<=s;j++){
			f[i][j]=f[i][j-1]+p[j][j]-p[j][i-1];
		}
	}
	dp[0][0]=0;
	for(int a1=1;a1<=s;a1++){//前a1行
		for(int a2=1;a2<=k;a2++){//划分a2个机舱
			for(int a3=a2;a3<=a1;a3++){在a3处断开
				dp[a1][a2]=min(dp[a1][a2],dp[a3-1][a2-1]+f[a3][a1]);
			}
		}
	} 
	printf("%d\n",dp[s][k]);
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!