数学建模之商人过河(编程法)

商人安全过河

  • 数学建模培训第一天
    • 题目描述
    • 题目分析
    • 商人过河C++源码

数学建模培训第一天

题目描述

在这里插入图片描述
第一问:商人和随从共三对,小船容量2人?
第二问:四名商人各带一名随从,小船容量3人?
第三问:假设小船容量三人,最多可以有几对商人及随从安全过河?

题目分析

多步决策问题
方法1:图解法(不做介绍)

方法2:编程法(易于推广)

第一步:表示状态矩阵,三维(商人数量,随从数量,小船所在侧)
S={(x,y)|x=0,y=0,1,2,3,…,n;x=n,y=0,1,2,…,n;x=y=0,1,…,n}
第二步:状态转移集合
Sk=Sk-1+(-1)kdk
第三步:深度优先搜索

商人过河C++源码

#include<iostream>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;

typedef long long ll;
const ll inf=(ll)((1<<30)+(-1+(ll)(1<<30)))<<30;
const ll MAX=1e3;
ll N;                       ///商人与随从的对数
ll M;                       ///小船的容量
bool exist[MAX][MAX][2];    ///状态存在的可能性,0:船在左侧;1:船在右侧

ll d_max;              ///小船承载人员的种类
ll d[MAX][2];          ///小船可承载人员类型及个数,0:商人;1:随从

ll num=0,min_num=0;    ///有效方案数,最少次数的方案数
ll smin_move=inf;

struct node
{
    ll x,y;
    bool side;
    node(ll x,ll y,bool side):x(x),y(y),side(side){}
};
stack<node> Stack,min_stack;

void init()             ///初始化
{
    ///状态矩阵的初始化
    exist[N][0][1]=exist[N][0][0]=exist[0][0][1]=exist[0][0][0]=1;
    for(ll i=1;i<=N;i++)
        exist[N][i][0]=exist[N][i][1]=exist[0][i][0]=exist[i][i][0]=exist[0][i][1]=exist[i][i][1]=1;

    ///小船可承载人员类型及个数的初始化
    d_max=0;
    for(ll i=1;i<=M;i++)
    {
        d[d_max][0]=0;
        d[d_max][1]=i;
        d_max++;
    }
    for(ll i=1;i<=M;i++)
    {
        ll j_max=min(i,M-i);
        for(ll j=0;j<=j_max;j++)
        {
            d[d_max][0]=i;
            d[d_max][1]=j;
            d_max++;
        }
    }
}

ll dfs(ll x,ll y,bool side)         ///深度优先搜索
{
    ll min_move=inf;
    exist[x][y][side]=0;
    if(!x&&!y)
    {
        num++;
        min_move=Stack.size();
        if(min_move==smin_move)
            min_num++;
        else if(min_move<smin_move)
        {
            min_stack=Stack;
            min_num=1;
            smin_move=min_move;
        }
    }
    else
    {
        ll t=side?1:-1;
        for(ll i=0;i<d_max;i++)
        {
            ll x_next=t*d[i][0]+x;
            ll y_next=t*d[i][1]+y;
            if(x_next>=0&&y_next>=0&&x_next<=N&&y_next<=N&&exist[x_next][y_next][!side])
            {
                Stack.push(node(x_next,y_next,!side));
                min_move=min(min_move,dfs(x_next,y_next,!side));
                Stack.pop();
            }
        }
    }
    exist[x][y][side]=1;
    return min_move;
}

void solve()
{
    Stack.push(node(N,N,0));
    ll min_move=dfs(N,N,0);
    if(min_move!=inf)           ///输出结果
    {
        stack<node> temp=min_stack;
        cout<<"例如:(0,0)";
        temp.pop();
        while(!temp.empty())
        {
            node dot=temp.top();
            temp.pop();
            cout<<"<-"<<'('<<dot.x<<','<<dot.y<<')';
        }
        cout<<endl;
        cout<<"最少乘船次数:"<<min_move-1<<endl;
        cout<<"有效方案数:"<<num<<endl;          ///不走回头路
        cout<<"最少次数的有效方案数:"<<min_num<<endl;
    }
    else
        cout<<"无法过河!"<<endl;
}

int main()
{
    cout<<"商人与随从的对数:";
    cin>>N;
    cout<<"小船的容量:";
    cin>>M;
    init();
    solve();
    return 0;
}


你可能感兴趣的:(数学建模)