zoj 1022 Parallel Expectations

博客详细讨论了Zoj 1022问题中并行期望的概念,介绍了如何计算在执行不同指令组合后达到特定状态的概率。文章通过源代码展示了解决方案,解释了如何从已执行的指令数推导出概率状态转移,并提到了程序1和程序2的总指令数在概率计算中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设目前的状态是已经执行完程序1的第i条指令,并且执行完了程序2的第j条指令,那么记到达该状态的概率为p[i][j]

那么到达p[i][j]状态有两种可能,一种是程序1已经执行了i-1条指令,程序2执行了j条指令,另一种是程序1执行了i条指令,程序2执行了j-1条指令

所以我们有

if (i < p_line1&&j < p_line2){
	p1 = 0.5*prob[i - 1][j]; p2 =0.5* prob[i][j - 1];
}
else if (i < p_line1){//如果程序2全部执行完了,那么执行程序1的概率不变了
	p1 = prob[i - 1][j]; p2 = 0.5*prob[i][j - 1];
}
else if (j < p_line2){//如果程序1全部执行完了,那么执行程序2的概率不再变化
	p1 = prob[i - 1][j] * 0.5; p2 = prob[i][j - 1];
}
else{
	p1 = prob[i - 1][j]; p2 = prob[i][j - 1];
}
prob[i][j] = p1 + p2;

p_line1表示的是程序1的总指令条数,p_line2表示的程序2的总指令条数

源代码(附注释)如下:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;

int t;
int number1, number2;
string word[3];
int line1, line2;

typedef struct{
	bool is_const;
	string name;
	double value;
}var;

typedef struct{
	int index1;
	int index2;
	char op;
}com;
com command[2][110];
var variable[150];
double prob[110][110],p1,p2,p;
double excute[110][110][40];

void resolve2(int aim,int source,int machine,char op,int current){
	command[machine][current].index1 = aim;
	command[machine][current].index2 = source;
	command[machine][current].op = op;
}

void resolve(int flag1,int flag2,int flag3,int machine,char op,int current){
	int R1 = 2 * machine;
	int R2 = 2 * machine + 1;
	resolve2(R1,flag2,machine,':',4*current+1);//记录每一条机器指令的操作数以及对应的操作符,便于后面的分析
	resolve2(R2,flag3,machine,':',4*current+2);
	resolve2(R1,R2,machine,op,4*current+3);
	resolve2(flag1,R1,machine,':',4*current+4);
}

int store_variable(string name,int &cur){
	if (name[0] >= '0'&&name[0] <= '9'){
		int value = 0;
		for (int i = 0; i < name.size(); i++){
			value = value * 10 + (name[i]-'0');
		}
		variable[cur].is_const = true;
		variable[cur].name = "const";
		variable[cur].value = value;
		return cur++;
	}
	else{
		for (int i = 0; i < cur; i++){
			if (variable[i].is_const) continue;
			if (variable[i].name == name) return i;
		}
		variable[cur].is_const = false;
		variable[cur].name = name;
		variable[cur].value = 0;
		return cur++;
	}
}

void init(){//variable中的前四个元素用来存储寄存器
	for (int i = 0; i < 4; i++){
		variable[i].is_const = true;
		variable[i].name = "Rx";
		variable[i].value = 0;
	}
}

int read_command(int machine,int& number3){//machine用来表示程序的编号
										  //number用来标识从第几个变量开始存储
	string s1;
	int lines = 0;
	while (getline(cin, s1)){
		if (s1 == "") continue;//如果当前读入的是回车字符,则继续读入
		if (s1 == "END")  break;
		string s="";
		for (int i = 0; i < s1.size(); i++){//去掉读入的字符串中的空格符,并且将所有的字母都统一成大写形式
			//便于后续的管理,注意题目中的Case insensitive
			if (s1[i] == ' ') continue;
			if (s1[i] >= 'a'&&s1[i] <= 'z'){
				s1[i] = toupper(s1[i]);
			}
			s+=s1[i];
		}
		lines++;
		int index1, index2, index3;
		for (int i = 0; i < s.size(); i++){
			if (s[i] == ':'){//记录冒号的位置
				index1 = i;
			}
			else if (s[i] == '+'||s[i]=='-'){//记录符号的位置
				index2 = i;
				break;
			}
		}
		word[0] = s.substr(0,index1);//提取变量名
		word[1] = s.substr(index1+2,index2-index1-2);
		word[2] = s.substr(index2+1);
		int flag1, flag2, flag3;
		flag1 = store_variable(word[0], number3);//如果变量在variabel数组中已经存在,那么就直接返回下标,否则就在variable中找一个位置存储
		//同时让variable中的已用长度增加1
		flag2 = store_variable(word[1], number3);
		flag3 = store_variable(word[2], number3);
		resolve(flag1, flag2, flag3, machine, s[index2],lines-1);//将每行代码翻译成为对应的四条机器指令
	}
	return lines;
}

void cal(double* temp11,int index, int machine){
	int index1 = command[machine][index].index1;
	int index2 = command[machine][index].index2;
	if (command[machine][index].op == ':'){
		temp11[index1] = temp11[index2];
	}
	else if (command[machine][index].op == '+'){
		temp11[index1] += temp11[index2];
	}
	else if (command[machine][index].op == '-'){
		temp11[index1] -= temp11[index2];
	}
}

bool compare(var a,var b){
	if (a.is_const != b.is_const) return a.is_const > b.is_const;
	else{
		return a.name < b.name;
	}
}

void dp(int p_line1,int p_line2){
	prob[0][0] = 1;
	for (int i = 0; i < number2; i++){//在所有代码开始执行之前保存已有的每一个常量和变量的值
		excute[0][0][i] = variable[i].value;
	}
	for (int i = 1; i <= p_line1; i++){//仅仅开始执行第一段程序的每一行所出现的结果都保存
		prob[i][0] = 0.5*prob[i-1][0];
		for (int k = 0; k < number2; k++) excute[i][0][k] = excute[i-1][0][k];
		cal(excute[i][0],i,0);
	}
	for (int j = 1; j <= p_line2; j++){//仅仅开始执行第二段程序的每一行所出现的结果都保存
		prob[0][j] = 0.5*prob[0][j-1];
		for (int k = 0; k < number2; k++) excute[0][j][k] = excute[0][j-1][k];
		cal(excute[0][j],j,1);
	}
	double temp1[40], temp2[40];//分析交叉执行的情况
	for (int i = 1; i <= p_line1; i++){
		for (int j = 1; j <= p_line2; j++){
			for (int k = 0; k < number2; k++){
				temp1[k] = excute[i - 1][j][k];
				temp2[k] = excute[i][j - 1][k];
			}
			cal(temp1, i, 0);
			cal(temp2, j, 1);
			if (i < p_line1&&j < p_line2){
				p1 = 0.5*prob[i - 1][j]; p2 =0.5* prob[i][j - 1];
			}
			else if (i < p_line1){
				p1 = prob[i - 1][j]; p2 = 0.5*prob[i][j - 1];
			}
			else if (j < p_line2){
				p1 = prob[i - 1][j] * 0.5; p2 = prob[i][j - 1];
			}
			else{
				p1 = prob[i - 1][j]; p2 = prob[i][j - 1];
			}
			prob[i][j] = p1 + p2;
			for (int k = 0; k < number2; k++){
				excute[i][j][k] = (p1*temp1[k] + p2*temp2[k]) / (prob[i][j]);
			}
		}
	}
	for (int k = 0; k < number2; k++){//利用variable保存交叉执行的最终结果
		variable[k].value = excute[p_line1][p_line2][k];
	}
	sort(variable+4,variable+number2,compare);//排序
	int start = 4;
	while (start < number2&&variable[start].is_const) start++;
	for (int i = start; i < number2; i++) printf("%.4lf\n",variable[i].value);//输出最终结果
}

int main(){
	cin >> t;//读入Case的数量
	string temp;
	getline(cin,temp);//消除回车符
	while (t--){
		init();//初始化,在所定义的variable中,前两个用作第一个程序的寄存器,后两个用作第二个程序的寄存器
		number1 = 4;//后面变量的记录从第四个开始
		line1 = read_command(0,number1);//开始读入第一个程序
		number2 = number1;
		line2 = read_command(1,number2);//开始读入第二个程序
		dp(4*line1,4*line2);//开始进行计算
		if (t) printf("\n");
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值