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。
【解题报告】