修道士和野人问题
来源:互联网 发布:在淘宝退货卖家拒收 编辑:程序博客网 时间:2024/05/07 09:52
优化版 v1.0
i7 6500U 4G内存 2s内可以对 1000 2000 输入建图
建图复杂度取决于边数。
description:
假设有n个修道士和n个野人准备渡河,但只有一条能容纳c人的小船,为了防止野人侵犯修道士,要求无论在何处,修道士的个数不得少于野人的人数(除非修道士个数为0)。如果两种人都会划船,试设计一个算法,确定他们能否渡过河去,若能,则给出一个小船来回次数最少的最佳方案并求出所有的解。
sample input:
3 2 //野人修道士各三个,船限载2人
4 2
1000 2000
#include <bits/stdc++.h>using namespace std;const int MAXN=1e7+10;typedef struct Node{ int x1,x2;bool dir; bool operator < (const Node &a)const{ if(x1==a.x1){ if(x2==a.x2){ return dir<a.dir; }else return x2<a.x2; }else return x1<a.x1; }}Node;int n,k,tot;map <Node,int> mp;Node nodes[MAXN];int fa[MAXN],dep[MAXN];vector <int> edge[MAXN];int vis[MAXN];int sta[MAXN],head;bool output_control;void ini(){ memset(dep,0,sizeof(dep));memset(fa,-1,sizeof(fa));memset(vis,0,sizeof(vis)); mp.clear();for(int i=0;i<=tot;i++) edge[i].clear(); tot=0;head=-1;}void build(){ int lim1,lim2; queue <Node> que;Node now={n,n,0},pos; que.push(now); nodes[++tot]=now; mp[now]=tot; fa[tot]=-1; bool lim_control=0; while(!que.empty()){ now=que.front();que.pop(); int x=mp[now],y; lim1=now.x1-now.x2; lim2=(n-now.x1)-(n-now.x2); if(now.dir){ pos.dir=0; if(now.x1!=0) lim_control=1; else lim_control=0; for(int j=1;j<=n-now.x2&&j<=k;j++){//i==0 if(lim_control&&j>lim1) break; pos.x1=now.x1;pos.x2=now.x2+j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } for(int i=1;i<n-now.x1&&i<=k;i++){//i!=0 for(int j=max(0,i-lim2);j<=i&&j<=n-now.x2&&(i+j)<=k&&(j-i)<=lim1;j++){ pos.x1=now.x1+i;pos.x2=now.x2+j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } } if(now.x1!=n) for(int i=n-now.x1;i<=n-now.x1&&i<=k;i++){ for(int j=0;j<=i&&j<=n-now.x2&&(i+j)<=k&&(j-i)<=lim1;j++){ pos.x1=now.x1+i;pos.x2=now.x2+j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } } }else{ pos.dir=1; if(now.x1!=n) lim_control=1; else lim_control=0; for(int j=1;j<=now.x2&&j<=k;j++){//i==0 if(lim_control&&j>lim2) break; pos.x1=now.x1;pos.x2=now.x2-j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } for(int i=1;i<now.x1&&i<=k;i++){//i<now.x1 for(int j=max(0,i-lim1);j<=i&&j<=now.x2&&(i+j)<=k&&(j-i)<=lim2;j++){ pos.x1=now.x1-i;pos.x2=now.x2-j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } } if(now.x1!=0) for(int i=now.x1;i<=now.x1&&i<=k;i++){//i<now.x1 for(int j=0;j<=i&&j<=now.x2&&(i+j)<=k&&(j-i)<=lim2;j++){ pos.x1=now.x1-i;pos.x2=now.x2-j; if(mp[pos]==0){ mp[pos]=++tot; nodes[tot]=pos; if(pos.x1!=0||pos.x2!=0) que.push(pos); } y=mp[pos]; edge[x].push_back(y); } } } }}void show_way(int x){ if(x==-1) return ; show_way(fa[x]); cout<<"Node: "<<x<<" position1: "<<nodes[x].x1<<" "<<nodes[x].x2<<" position2: "<<n-nodes[x].x1<<" "<<n-nodes[x].x2<<" direction: "<<nodes[x].dir<<endl;}void solve(){ int now,pos,len,lim=tot+1; queue <int> que; que.push(1); dep[1]=1; while(!que.empty()){ now=que.front(); que.pop(); len=edge[now].size(); for(int i=0;i<len;i++){ pos=edge[now][i]; if(!dep[pos]){ dep[pos]=dep[now]+1; fa[pos]=now; if(edge[pos].empty()){ cout<<"We need at least "<<dep[pos]-1<<" steps to solve the problem."<<endl; show_way(pos); cout<<endl; return ; } else que.push(pos); } } } if(lim==tot+1) puts("Sorry, no answer");}void show_path(){ cout<<"feasible path: "<<endl; for(int i=0;i<=head;i++) cout<<"Node: "<<sta[i]<<" position1: "<<nodes[sta[i]].x1<<" "<<nodes[sta[i]].x2<<" position2: "<<n-nodes[sta[i]].x1<<" "<<n-nodes[sta[i]].x2<<" direction: "<<nodes[sta[i]].dir<<endl; cout<<endl;}int dfs(int now,int left){ vis[now]=1; sta[++head]=now; int len=edge[now].size(),pos; int ans=0; if(len==0){ if(!output_control) show_path(); ans++; }else{ if(left>0){ for(int i=0;i<len;i++){ pos=edge[now][i]; if(!vis[pos]) ans+=dfs(pos,left-1); } } } vis[now]=0; head--; return ans;}void search_all(){ cout<<"Please enter the step limit: "; int p;cin>>p;cout<<endl; cout<<"Print all the path?(Y/N): "; char t;cin>>t; output_control=(t=='Y')?0:1; head=-1; cout<<"There are total "<<dfs(1,p)<<" answer(s) with the step limit of "<<p<<"."<<endl;}void debug(){ cout<<"tot: "<<tot<<endl; int edges=0; for(int i=1;i<=tot;i++) edges+=edge[i].size(); cout<<"edges: "<<edges<<endl; cout<<"show nodes?(Y/N)"<<endl; char t;cin>>t; if(t=='Y') for(int i=1;i<=tot;i++) cout<<i<<": "<<nodes[i].x1<<' '<<nodes[i].x2<<' '<<nodes[i].dir<<endl; cout<<"show edges?(Y/N)"<<endl; cin>>t; if(t=='Y') for(int i=1;i<=tot;i++){ cout<<i<<": "; for(int j=0;j<edge[i].size();j++) cout<<edge[i][j]<<' '; cout<<endl; }}int main(){ while(1){ system("cls"); cout<<"please enter the number of monk(s) or barbarian(s) and load limit of ship ( please separate them by space ): "; cin>>n>>k; cout<<endl; build(); while(1){ cout<<"1.Find the shortest path"<<endl; cout<<"2.Find the all the path with step limit x"<<endl; cout<<"3.Change the input"<<endl; cout<<"4.Developer Mode"<<endl; cout<<"Please enter 1 2 3 or 4 to continue: "; int p; cin>>p; if(p==1) solve(); else if(p==2) search_all(); else if(p==4) debug(); else break; system("pause"); } ini(); }}
当然我们也可以不建图,直接bfs求最短路或dfs求定长路径。复杂度会减小很多,改改就行。
阅读全文
0 0
- 修道士和野人问题
- 2.修道士和野人问题
- 修道士与野人问题
- 修道士和野人
- 请教“修道士与野人问题”
- 修道士和野人过河问题 A*算法 人工智能
- 野人与修道士问题的Ruby实现
- C++习题:野人与修道士过河问题
- prolog学习_修道士野人问题
- 修道士与野人问题——C++源代码,伪代码,详细分析
- 传教士和野人过河问题
- 【算法】传教士和野人问题
- 修道士过河问题
- 修道士过河问题
- 传教士和野人问题(Missionaries and Cannibals)
- 传教士和野人问题解题思路
- 【人工智能】传教士和野人问题(M-C问题)
- 野人和传教士过河问题的C语言源代码
- 关于支付成功,实现页面跳转方案
- NodeJS
- php实现定时任务
- 高仿APP——元贝驾考(一)FragmentUtils
- NP 完全问题8.3
- 修道士和野人问题
- react native 相册功能
- django post和get方法获取数据 数据在模板上的遍历
- 按日期查询
- guava之只读、函数式编程(过滤、转换)
- ROS机器人操作系统的安装、配置与初级教程 1
- 二叉查找树的简单实现
- ffmpeg参数解释--中文详细
- .html().text().val() 三者的区别