NOIP 2005 解题报告(过河)

    xiaoxiao2021-03-25  103

    2.过河(river.pas/c/cpp) 【问题描述】 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。 题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。 【输入文件】 输入文件river.in的第一行有一个正整数L(1 <= L <= 10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。 【输出文件】 输出文件river.out只包括一个整数,表示青蛙过河最少需要踩到的石子数。 【数据规模】 对于30%的数据,L <= 10000; 对于全部的数据,L <= 10^9。 【解题报告】 最简单的DP方式不难想到,但是L的长度如果是10的9此方的话,直接DP看定要完蛋。 但是可以发现,即使L再大,石子的个数也在100以内,所以说可以采用路径压缩。 至于怎么压的话,可以100,100地压,也可以根据t的值来压(其实不用压的太紧)。

    代码如下:

    #include<cstdio> #include<cstring> using namespace std; int L,k; int S,T,M,i,j,min; long stone[102],b[10005]; int Num[10005]; int X[120]; int main() { freopen("river.in","r",stdin); freopen("river.out","w",stdout); memset(Num,-1,sizeof(Num)); memset(b,0,sizeof(b)); scanf("%d",&L); scanf("%d%d%d",&S,&T,&M); for (i=0;i<M;i++) scanf("%d",&stone[i]); if(S==T) { min = 0; for (i=0;i<M;i++) { if (stone[i] % S == 0) min++; } printf("%d",min); return 0; } for (i=0;i<M-1;i++) { for (j=0;j<M-i-1;j++) if(stone[j]>stone[j+1]) { int temp; temp = stone[j]; stone[j]=stone[j+1]; stone[j+1]=temp; } } stone[M]=L; for(i=0;i<M;i++) X[i]=stone[i+1]-stone[i]; if (stone[0]>90) { k = stone[0]-90; for(i=0;i<=M;i++) stone[i] -= k; } for (i=1;i<=M;i++) { if (stone[i]-stone[i-1]>90) { k = stone[i]-stone[i-1]-90; for(j=i;j<=M;j++) stone[j] -= k; } } for (i=0;i<M;i++) b[stone[i]]=1; Num[0]=0; for (i=S;i<stone[M]+T;i++) { min = 101; for (j=i-T;j<=i-S;j++) { if (Num[j]<min && Num[j]!=-1&&j>=0) min=Num[j]; } if (min!=101) Num[i]=min+b[i]; } min=101; for (i=stone[M];i<stone[M]+T;i++) { if (Num[i]<min&&Num[i]!= -1) min = Num[i]; } printf("%d",min); return 0; }

    3.篝火晚会(fire.pas/c/cpp) 【问题描述】 佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”。在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会。一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,而实际上每个人都有两个最希望相邻的同学。如何下命令调整同学的次序,形成新的一个圈,使之符合同学们的意愿,成为摆在佳佳面前的一大难题。 佳佳可向同学们下达命令,每一个命令的形式如下: (b1, b2,… bm-1, bm) 这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是(b1, b2,… bm-1, bm)的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。 执行每个命令都需要一些代价。我们假定如果一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,你能帮助佳佳吗? 【输入文件】 输入文件fire.in的第一行是一个整数n(3 <= n <= 50000),表示一共有n个同学。其后n行每行包括两个不同的正整数,以一个空格隔开,分别表示编号是1的同学最希望相邻的两个同学的编号,编号是2的同学最希望相邻的两个同学的编号,……,编号是n的同学最希望相邻的两个同学的编号。 【输出文件】 输出文件fire.out包括一行,这一行只包含一个整数,为最小的总代价。如果无论怎么调整都不能符合每个同学的愿望,则输出-1。 【解题报告】

    转载请注明原文地址: https://ju.6miu.com/read-23293.html

    最新回复(0)