逃狱的汉尼拔博士

题干:

杀人狂魔汉尼拔博士逃狱了。通缉令发布后,大量军警出动并实施全天候追捕,不过狡猾的汉尼拔博士并没有落网。过了d日后,束手无策的警察们拜访了有着“编程天才”之称的查理教授。查理教授对汉尼拔博士留在监狱的笔记本进行分析后,做出了如下假设。

  1. )汉尼拔博士为了避开检查,只走山路;
  2. )汉尼拔博士越狱当天选择了与监狱相邻的村子之一作为藏身之处;
  3. )汉尼拔博士为了逃避追捕,每天往一个相邻的村子逃窜。

为了验证假设,教授找到了与监狱所在村子以山路连接的n个村子的地图。汉尼拔博士会按照此假设行动,而且会随机选择一个备选的村子。编写程序计算d日后汉尼拔博士在各个村子的概率。
例如监狱在第三个村子,逃狱后的汉尼拔博士会在0、1、2、4、5中任意选择一个村子藏身。因此,1天后汉尼拔博士藏在第0号村子的概率是1/5,两天后藏在第1号村子的概率是1/15。
在这里插入图片描述

输入:

第一行输入测试用例的个数C(1≤C≤50)。之后各行输入地图上显示的村子个数 N(2≤N≤50)和逃狱后经过的天数D(1≤D≤100),以及监狱所在村子的号码P(0≤P<N),村子的号码由0到N-1的数字组成。之后N行里各输入N个整数,形成一个序列A。第i行j列的数值A[i][j]如果等于1,就表示从第i号村子到第j号村子有山路可走;如果是0,则表示无路可通。接下来的一行输入要计算概率的村子的个数T(0≤T<N),最后一行以整数型输入要计算概率的村子的号码Q(0≤Q<N)。
如果一个村子与另一个村子相连,那么相反的路径也必定存在。可假设一个村子连接到自身的路径不存在。

输出:

每个测试用例以T个实数输出汉尼拔博士可能藏匿的概率。存在小于10-7的绝对/相对误差的答案将被视为正确答案。

示例输入值:

2
5 2 0
0 1 1 1 0
1 0 0 0 1
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0
3
0 2 4
8 2 3
0 1 1 1 0 0 0 0
1 0 0 1 0 0 0 0
1 0 0 1 0 0 0 0
1 1 1 0 1 1 0 0
0 0 0 1 0 0 1 1
0 0 0 1 0 0 0 1
0 0 0 0 1 0 0 0
0 0 0 0 1 1 0 0
4
3 1 2 6

示例输出值:

0.83333333 0.00000000 0.16666667
0.43333333 0.06666667 0.06666667 0.06666667

分析:

——我懒得写了,代码有注释。

代码:


#include <iostream>

using namespace std;

int C;		//使用次数
int N;		//村子个数
int D;		//逃跑天数
int p;		//监狱所在地
int T;		//计算的村子
int Q[50];		//需要计算的村子(多个)

double A[50][50] = {};		//每个村子的联通情况
double B[100][50] = {};		//用于计算储存概率---100天 50个村
double S[50] = {};			//用于储存每个村子有多少联通村
double R[50][50] = {};		//用于储存结果


void ZxxInput() {

	cout << "请输入村子个数、逃跑天数、监狱所在地";
	cin >> N>>D>>p;		//输入所需数据
	B[0][p] = 1;		//第0天在p村的概率为1


	cout << "输入每两个村子是否联通"<<endl;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> A[i][j];
			S[i] = S[i] + A[i][j];			//计算每个村子有多少联通村
		}
	}

	cout << "输入要计算几个村子";
	cin >> T;

	cout << "输入T个村子的编号";
	for(int i=0;i<T;i++){
		cin >> Q[i];
	}
	
}

void ZxxDeal() {		//概率运算处理

	cout << "开始运算处理" << endl;
	for (int i = 1; i <= D; i++) {				//计算每一天的结果
		for (int j = 0; j < N; j++) {			//计算每一村的结果
			for (int k = 0; k < N; k++) {		//第i天,j个村子的结果
												遍历k个村子


				if (S[k] != 0) {
					B[i][j] = (B[i - 1][k] * (1 / S[k]) * A[j][k]) + B[i][j];
				}
				else
				{
					continue;
				}



			}
		}
	}
}

void ZxxARM(int n) {		//多次的结果储存

	for (int i = 0; i < T; i++) {
		R[n][i] = B[D][Q[i]];
	}
	cout << endl;
}

void ZxxPrint() {			//输出最后结果
	
	for (int i = 0; i <C; i++) {
		for (int j = 0; j < 50; j++) {
			if (R[i][j] <0) {
				break;
			}
			cout << R[i][j] << "  ";
			
		}cout << endl;
	}
	
}

void ZxxDie() {		//每次都需要将数组归零

	for (int i = 0; i < 100; i++) {
		for (int j = 0; j < 50; j++) {
			B[i][j] = 0;
			S[j] = 0;
		}
	}

}

void ZxxDieR() {		//结果数组的初始化

	for (int i = 0; i < 50; i++) {
		for (int j = 0; j < 50; j++) {
			R[i][j] = -1;
		}
	}
}



int main()
{
	cout << "输入模拟次数";
	cin >> C;
	ZxxDieR();
	for(int i=0;i<C;i++){

		ZxxInput();
		ZxxDeal();
		ZxxARM(i);
		ZxxDie();
	}
	ZxxPrint();
	return 0;
}

好吧还是写点分析吧。。。

首先分析问题的解法。这个代码每次的运算都会算出博士在某个村子的概率。然后下一天的概率是由前一天的概率得出。
那么这一天的概率如何得出:首先设博士在M村,这是第0天,在这个村子的概率为1;假设与M村相连的有K个村子,那么第一天,博士在这K个村子之一的概率为(1/K)乘1, 这里为什么要乘1,因为这个结果的上一天的概率为1。则存储第一天的情况为这K个村子、每个村子的概率为1/K。同理,第二天的情况某个村子(假设这个村子的前一天村子连接了N个村子)的情况应该是(1/K)乘(1/N)。。。。。。。
以此类推。
吐槽一点:代码中的ZxxARM()方法纯粹是为了迎合输入输出方式。(多次输入,一次输出) 另外因为这样,就需要在每次的运算后归零输入矩阵(InPut()方法),不然上次的输出会参与进这次的运算。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值