想问个程序题???

meiyitian62 2013-11-15 05:31:35
设有N(本次设计控制在1-9之间,下同)个传教士和N个野人同在河的左岸,他们都要到对岸去,河里只有一条船,他们都会划船,但每次渡河至多只能乘N人;如果在任何一边河岸上,野人的数量超过传教士,野人就要吃掉传教士。问怎样才能用船将N个传教士和N个野人从左岸都渡到右岸,又不会发生传教士被吃的事件呢?
...全文
211 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
meiyitian62 2013-11-16
  • 打赏
  • 举报
回复
引用 13 楼 meiyitian62 的回复:
[quote=引用 8 楼 byxbai1989 的回复:] N为2的倍数时, 第一次带N/2传教士 N/2野人。 再把N/2野人载回来。 1、第二次带N个野人,再回来N/2传教士,第三次载N个传教士。 2、第二次只带N/2个传教士。第三次载N个野人。(好像比1好)
如果按你的第一次再把N/2个野人载回来,那么左岸的就是N/2个传教士和N个野人,这时野人数量比传教士多,传教士就会被吃掉[/quote]
引用 8 楼 byxbai1989 的回复:
N为2的倍数时, 第一次带N/2传教士 N/2野人。 再把N/2野人载回来。 1、第二次带N个野人,再回来N/2传教士,第三次载N个传教士。 2、第二次只带N/2个传教士。第三次载N个野人。(好像比1好)
第一次带N/2个传教士和N/2个野人到右岸,再把N/2个传教士带到左岸。此时左岸N个传教士, N/2个野人 第二次带N个传教士到右岸,再把N/2个野人带回左岸。此时左岸N个野人,右岸N个传教士 第三次带N个野人到右岸,这样全部都到右岸
meiyitian62 2013-11-16
  • 打赏
  • 举报
回复
引用 12 楼 uuuououlcz 的回复:
实际上是指定起点终点的图的路径选择问题,每一个点不能遍历两次(因为,如果这个点曾经遍历过,那么只有两种可能:一是从这个点不能到达终点,二是从这个点到达终点的路径已经找到了),可以用DFS,且由于问题中可能的状态点只有2*N*N个,所以DFS的最差复杂度即O(2*N*N),以下代码仅供参考:

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define MAX_PERSON 9
#define MAX_BEAST  9

const int Left = 0, Right = 1;

struct Record{
    int person;
    int beast;
    int direction;
};

void printRecord(const vector<Record>& v)
{
    for(int i = 0, s = v.size(); i < s; ++i){
        printf("%d times: ", i+1);
        if(v[i].person > 0) printf("%d people", v[i].person);
        if(v[i].person > 0 && v[i].beast > 0) printf(" and ");
        if(v[i].beast > 0) printf("%d beast", v[i].beast);
        if(v[i].direction == Left) puts(" go from right bank to left bank");
        else puts(" go from left bank to right bank");
    }
}

int totalPerson, totalBeast, boatCapacity;  //known conditions
bool state[2][MAX_PERSON+1][MAX_BEAST+1];   //state: left bank's person and beast number with the boat's position

bool goAcrossRiver(const int personOnShore, const int beastOnShore, int atBank, vector<Record>& v)
{
    //all have crossed the river
    if(atBank == Right && personOnShore == totalPerson && beastOnShore == totalBeast){
        return true;
    }

    //figure out how many people and beasts on other side
    int personOtherSide = totalPerson - personOnShore;
    int beastOtherSide = totalBeast - beastOnShore;

    //mark state traversed
    if(atBank == Left) state[Left][personOnShore][beastOnShore] = true;
    else state[Right][personOtherSide][beastOtherSide] = true;

    //continue to drive boat to other side
    Record tmp;
    for(int personToGo = 0; personToGo <= personOnShore; ++personToGo){
        for(int beastToGo = 0; beastToGo <= beastOnShore; ++beastToGo){
            //if too many to get on boat
            if(personToGo + beastToGo > boatCapacity) break;
            //if no one to drive
            if(personToGo == 0 && beastToGo == 0) continue;
            //if beast number > person number on this side
            if(personOnShore - personToGo > 0 && beastOnShore - beastToGo > personOnShore - personToGo) continue;
            //if beast number > person number on other side
            if(personOtherSide + personToGo > 0 && beastOtherSide + beastToGo > personOtherSide + personToGo) continue;
            //if next state has been traversed
            if(atBank == Left && state[Right][personOnShore - personToGo][beastOnShore - beastToGo]) continue;
            if(atBank == Right && state[Left][personOtherSide + personToGo][beastOtherSide + beastToGo]) continue;
            //only in this case, can crossing river be done, and record before crossing
            tmp.person = personToGo;
            tmp.beast = beastToGo;
            tmp.direction = !atBank;
            v.push_back(tmp);
            if(goAcrossRiver(personOtherSide + personToGo, beastOtherSide + beastToGo, !atBank, v)) return true;//a path has been found
            v.pop_back();
        }
    }

    //no path from current state to final state
    return false;
}


int main()
{
    vector<Record> rec;

    for(int i = 1; i <= MAX_PERSON; ++i){
        totalPerson = totalBeast = boatCapacity = i;
        memset(state, false, sizeof(state));

        printf("%d people and %d beasts want to cross the river:\n", totalPerson, totalBeast);
        if(goAcrossRiver(totalPerson, totalBeast, Left, rec)) printRecord(rec);
        else puts("No way!");

        getchar();
    }

    return 0;
}
最后,需要注意的是,由于DFS搜索的盲目性,可能得到的结果不是最优的
牛气
meiyitian62 2013-11-16
  • 打赏
  • 举报
回复
引用 8 楼 byxbai1989 的回复:
N为2的倍数时, 第一次带N/2传教士 N/2野人。 再把N/2野人载回来。 1、第二次带N个野人,再回来N/2传教士,第三次载N个传教士。 2、第二次只带N/2个传教士。第三次载N个野人。(好像比1好)
如果按你的第一次再把N/2个野人载回来,那么左岸的就是N/2个传教士和N个野人,这时野人数量比传教士多,传教士就会被吃掉
还有多远 2013-11-16
  • 打赏
  • 举报
回复
实际上是指定起点终点的图的路径选择问题,每一个点不能遍历两次(因为,如果这个点曾经遍历过,那么只有两种可能:一是从这个点不能到达终点,二是从这个点到达终点的路径已经找到了),可以用DFS,且由于问题中可能的状态点只有2*N*N个,所以DFS的最差复杂度即O(2*N*N),以下代码仅供参考:

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define MAX_PERSON 9
#define MAX_BEAST  9

const int Left = 0, Right = 1;

struct Record{
    int person;
    int beast;
    int direction;
};

void printRecord(const vector<Record>& v)
{
    for(int i = 0, s = v.size(); i < s; ++i){
        printf("%d times: ", i+1);
        if(v[i].person > 0) printf("%d people", v[i].person);
        if(v[i].person > 0 && v[i].beast > 0) printf(" and ");
        if(v[i].beast > 0) printf("%d beast", v[i].beast);
        if(v[i].direction == Left) puts(" go from right bank to left bank");
        else puts(" go from left bank to right bank");
    }
}

int totalPerson, totalBeast, boatCapacity;  //known conditions
bool state[2][MAX_PERSON+1][MAX_BEAST+1];   //state: left bank's person and beast number with the boat's position

bool goAcrossRiver(const int personOnShore, const int beastOnShore, int atBank, vector<Record>& v)
{
    //all have crossed the river
    if(atBank == Right && personOnShore == totalPerson && beastOnShore == totalBeast){
        return true;
    }

    //figure out how many people and beasts on other side
    int personOtherSide = totalPerson - personOnShore;
    int beastOtherSide = totalBeast - beastOnShore;

    //mark state traversed
    if(atBank == Left) state[Left][personOnShore][beastOnShore] = true;
    else state[Right][personOtherSide][beastOtherSide] = true;

    //continue to drive boat to other side
    Record tmp;
    for(int personToGo = 0; personToGo <= personOnShore; ++personToGo){
        for(int beastToGo = 0; beastToGo <= beastOnShore; ++beastToGo){
            //if too many to get on boat
            if(personToGo + beastToGo > boatCapacity) break;
            //if no one to drive
            if(personToGo == 0 && beastToGo == 0) continue;
            //if beast number > person number on this side
            if(personOnShore - personToGo > 0 && beastOnShore - beastToGo > personOnShore - personToGo) continue;
            //if beast number > person number on other side
            if(personOtherSide + personToGo > 0 && beastOtherSide + beastToGo > personOtherSide + personToGo) continue;
            //if next state has been traversed
            if(atBank == Left && state[Right][personOnShore - personToGo][beastOnShore - beastToGo]) continue;
            if(atBank == Right && state[Left][personOtherSide + personToGo][beastOtherSide + beastToGo]) continue;
            //only in this case, can crossing river be done, and record before crossing
            tmp.person = personToGo;
            tmp.beast = beastToGo;
            tmp.direction = !atBank;
            v.push_back(tmp);
            if(goAcrossRiver(personOtherSide + personToGo, beastOtherSide + beastToGo, !atBank, v)) return true;//a path has been found
            v.pop_back();
        }
    }

    //no path from current state to final state
    return false;
}


int main()
{
    vector<Record> rec;

    for(int i = 1; i <= MAX_PERSON; ++i){
        totalPerson = totalBeast = boatCapacity = i;
        memset(state, false, sizeof(state));

        printf("%d people and %d beasts want to cross the river:\n", totalPerson, totalBeast);
        if(goAcrossRiver(totalPerson, totalBeast, Left, rec)) printRecord(rec);
        else puts("No way!");

        getchar();
    }

    return 0;
}
最后,需要注意的是,由于DFS搜索的盲目性,可能得到的结果不是最优的
zxx178239 2013-11-15
  • 打赏
  • 举报
回复
引用 10 楼 wangdahu888 的回复:
[quote=引用 5 楼 u012183952 的回复:] [quote=引用 4 楼 wangdahu888 的回复:] 我七岁时就有人给我出过类似的题: 要带一只狗,一只鸡,一袋米过一座桥,但是一次只能通过人和其他一个物体,但是狗吃鸡,鸡吃米,问怎么过桥? 当时没做出来
这个怎么解? 人带狗->米->鸡这样的话第一次带狗过去剩下鸡和米不安全,人带鸡->狗->米或其他也不行,怎么破,解释下[/quote] 桥这头为A,桥那头为B。 人和鸡先过桥,留狗和米在A处,狗不吃米,所以很安全。 人把鸡留在桥那头即B处。人回到A处,再带狗过桥,过桥后,把狗留在B处,再把鸡带回到A处。然后,把鸡留在A处,带米到B处,与狗狗在一起。最后,人回到A处,带鸡过桥。这样,鸡,狗,米都过桥了。[/quote] 了解,带过来带过去呀!懂了
  • 打赏
  • 举报
回复
引用 5 楼 u012183952 的回复:
[quote=引用 4 楼 wangdahu888 的回复:] 我七岁时就有人给我出过类似的题: 要带一只狗,一只鸡,一袋米过一座桥,但是一次只能通过人和其他一个物体,但是狗吃鸡,鸡吃米,问怎么过桥? 当时没做出来
这个怎么解? 人带狗->米->鸡这样的话第一次带狗过去剩下鸡和米不安全,人带鸡->狗->米或其他也不行,怎么破,解释下[/quote] 桥这头为A,桥那头为B。 人和鸡先过桥,留狗和米在A处,狗不吃米,所以很安全。 人把鸡留在桥那头即B处。人回到A处,再带狗过桥,过桥后,把狗留在B处,再把鸡带回到A处。然后,把鸡留在A处,带米到B处,与狗狗在一起。最后,人回到A处,带鸡过桥。这样,鸡,狗,米都过桥了。
byxbai1989 2013-11-15
  • 打赏
  • 举报
回复
N不为2的整倍数时: 第一次载(N+1)/2野人 (N-1)/2传教士 再载回来(N-1)/2传教士 第二次载(N-1)/2 野人 第三次载N个传教士。 如果写在代码中,额,你再想想 。。?
byxbai1989 2013-11-15
  • 打赏
  • 举报
回复
N为2的倍数时, 第一次带N/2传教士 N/2野人。 再把N/2野人载回来。 1、第二次带N个野人,再回来N/2传教士,第三次载N个传教士。 2、第二次只带N/2个传教士。第三次载N个野人。(好像比1好)
meiyitian62 2013-11-15
  • 打赏
  • 举报
回复
引用 1 楼 nightkids_008 的回复:
你猜
卖萌可耻啊!
Sky丶Memory 2013-11-15
  • 打赏
  • 举报
回复
引用 3 楼 max_min_ 的回复:
折半带过去呗,然后再回相同的教士和野人回来重新载人啊! 保证每次来回载的野人和教士的人数是相同的就好了! 很简单吧!
貌似不行吧,如果N=2的时,就不能保证来回载的野人和教士的人数相同了,在临界条件需要进行判断的。 LZ可以去看下商人过河问题,你这个问题比商人过河问题相比之下,要简单点。
zxx178239 2013-11-15
  • 打赏
  • 举报
回复
引用 4 楼 wangdahu888 的回复:
我七岁时就有人给我出过类似的题: 要带一只狗,一只鸡,一袋米过一座桥,但是一次只能通过人和其他一个物体,但是狗吃鸡,鸡吃米,问怎么过桥? 当时没做出来
这个怎么解? 人带狗->米->鸡这样的话第一次带狗过去剩下鸡和米不安全,人带鸡->狗->米或其他也不行,怎么破,解释下
  • 打赏
  • 举报
回复
我七岁时就有人给我出过类似的题: 要带一只狗,一只鸡,一袋米过一座桥,但是一次只能通过人和其他一个物体,但是狗吃鸡,鸡吃米,问怎么过桥? 当时没做出来
max_min_ 2013-11-15
  • 打赏
  • 举报
回复
折半带过去呗,然后再回相同的教士和野人回来重新载人啊! 保证每次来回载的野人和教士的人数是相同的就好了! 很简单吧!
纯洁的老黄瓜 2013-11-15
  • 打赏
  • 举报
回复
我还以为是河里有咬人的鱼那道题
nightkids_008 2013-11-15
  • 打赏
  • 举报
回复
你猜

65,183

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧