过河——状压dp

Description

在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。

题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。

Input

第一行有一个正整数L(1 <= L <= 109),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。

Output

只包括一个整数,表示青蛙过河最少需要踩到的石子数。

Sample Input

10
2 3 5
2 3 5 6 7
Sample Output

2

#include <stdio.h>  
 #include <string.h>  
 #include<iostream>
#include<algorithm>
 using namespace std;
 int main()  
 {  
    int L ,temp,k;  
    int S,T,M,i,j,minn;  
    int stone[102],b[10000];  
    int Num[10000];  
    scanf("%ld",&L);  
    scanf("%d %d %d",&S,&T,&M);  
    for (i=0;i<M;i++)  
        scanf("%d",&stone[i]);  


    if (S!=T)  //两种情况,一是最大距离不等于最小距离
    {  
        sort(stone,stone+m);
        stone[M] = L;  //标记结束的位置,不能放循环外面

        if (stone[0]>20)  
        {                                      //第一个石头在20之后,无论什么情况,前面需要过石头的数量都为0
            k = stone[0]-20;  
            for(i=0;i<=M;i++)  
                stone[i] -= k;  
        }  
        for (i=1;i<=M;i++)  
        {  
            if (stone[i]-stone[i-1]>20)  
            {                                                //这个也是
                k = stone[i]-stone[i-1]-20;  
                for(j=i;j<=M;j++)  
                    stone[j] -= k;  
            }  
        }  


        memset(Num,125,sizeof(Num));  //这些一定不能放开头写
        memset(b,0,sizeof(b));  

        for (i=0;i<M;i++)  //标记石头在第几个位置 
            b[stone[i]] = 1;  


        Num[0] = 0;  
     minn=101;
        for (i=S;i<stone[M]+T;i++)  //考虑超出去的最远距离
        {  
         for(j=S;j<=T&&i-j>=0;j++)
         Num[i]=min(Num[i],Num[i-j]+b[i]);//我把我的代码放了进去,OK啦。
        }
        printf("%d",Num[stone[M]+T-1]);  
    }  
    else  //第二种是最大距离等于最小距离,此时只有一种情况
    {  
        minn= 0;  
        for (i=0;i<M;i++)  
        {  
            if (stone[i] % S == 0)  
                minn++;  
        }  
        printf("%d",minn);  
    }  
    return 0;  
 }  
农夫过河问题是一个经典的逻辑智力游戏,通常涉及到一位农夫要将一只狼、一只羊和一颗白菜带到河的对岸,但是他只有一艘船,船只能容纳他和另外一样物品(不包括船)。 在这个游戏中,农夫必须遵循以下规则: 1. 农夫可以驾驶船只过河,但是他必须在船上才能移动。 2. 狼和羊不能被留在一起,因为狼会吃羊。 3. 羊和白菜也不能被留在一起,因为羊会吃白菜。 你可以使用C语言来解决这个问题,下面是一个简单的程序实现: ```c #include <stdio.h> int main() { int farmer = 1, wolf = 1, goat = 1, cabbage = 1; // 1表示在左岸,0表示在右岸 printf("农夫过河问题解决方案:\n"); while (wolf || goat || cabbage) // 如果有任意一个在左岸,则继续循环 { if (farmer == 1) // 如果农夫在左岸 { if (wolf == 1 && goat == 1 && cabbage == 1) // 如果狼、羊、白菜都在左岸 { printf("农夫带着羊过河\n"); goat = 0; } else if (wolf == 1 && goat == 1 && cabbage == 0) // 如果狼、羊在左岸,白菜在右岸 { printf("农夫带着狼过河\n"); wolf = 0; } else if (wolf == 1 && goat == 0 && cabbage == 0) // 如果狼在左岸,羊、白菜在右岸 { printf("农夫带着羊过河\n"); goat = 1; } else if (wolf == 0 && goat == 1 && cabbage == 0) // 如果狼在右岸,羊、白菜在左岸 { printf("农夫带着白菜过河\n"); cabbage = 1; } else if (wolf == 0 && goat == 0 && cabbage == 1) // 如果狼、羊在右岸,白菜在左岸 { printf("农夫带着羊过河\n"); goat = 1; } } else // 如果农夫在右岸 { if (wolf == 0 && goat == 0 && cabbage == 0) // 如果狼、羊、白菜都在右岸 { printf("农夫带着狼过河\n"); wolf = 1; } else if (wolf == 0 && goat == 0 && cabbage == 1) // 如果狼、羊在右岸,白菜在左岸 { printf("农夫带着白菜过河\n"); cabbage = 0; } else if (wolf == 0 && goat == 1 && cabbage == 1) // 如果狼在右岸,羊、白菜在左岸 { printf("农夫带着狼过河\n"); wolf = 1; } else if (wolf == 1 && goat == 0 && cabbage == 1) // 如果狼、白菜在左岸,羊在右岸 { printf("农夫带着羊过河\n"); goat = 0; } else if (wolf == 1 && goat == 1 && cabbage == 0) // 如果狼在左岸,羊、白菜在右岸 { printf("农夫带着狼过河\n"); wolf = 0; } } farmer = 1 - farmer; // 农夫过河 } printf("农夫成功将狼、羊、白菜都带到了对岸!\n"); return 0; } ``` 在这个程序中,我们使用了四个变量来表示农夫、狼、羊、白菜的位置(1表示在左岸,0表示在右岸)。我们使用一个while循环,只要有任意一样物品在左岸,就继续循环。 在while循环中,我们根据当前的物品位置和农夫的位置,判断应该带哪一样物品过河。当农夫过河后,我们更新物品位置和农夫位置。当狼、羊、白菜都在右岸时,我们跳出循环,输出“农夫成功将狼、羊、白菜都带到了对岸!”。 这个程序只是一个简单的实现,可能存在一些小bug,但是它可以帮助你理解农夫过河问题的解决方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值