并行程序模拟(ACM/ICPC World Finals 1991)

2023-10-30

附上题目连接~concurrency simulator


本题为紫书数据结构基础篇第一道例题,是一道考察双端队列的模拟题,由于使用了STL,题目的难度和编程量大大降了下来,不过本菜鸟还是花了三个半小时才拿下了这道题,30msAC,可想见代码有多烂。

这是第一次做模拟题,第一感受是信息量有些大,不过仔细梳理后发现不过就几个点:模拟的主体是几个程序,程序由不超过25条5种类型的语句组成,每条语句都有固定的运行时间;使用等待队列和阻止队列管理程序,每个程序每次出队都有一个固定配额;理解lock和unlock语句的规则;当然还有共享的不超过26个的变量。

理解了题目接下来就是选取恰当的数据结构存储数据,并且编写输入和输出代码。这一部分是本菜鸟最头痛的部分,每次都固定带走一个半小时,但我相信这样的花费是值得的,因为一个程序的好坏甚至能否成功运行至少有一半得归结于如何将给定输入信息转化为程序信息,以及选择适当的数据结构方便信息的获取和检索。下面来说说我的思路:

可以看出,主要要处理的输入信息为程序的语句,首先可以看到语句中有许多不可控的空格,我们要想办法将它们剔除;其次计算机是不会认识这些语句的,我们需要让计算机认识它们,最直接的想法是每次将语句做程序中自己加入的字符串比较,但是这样会造成时空上的极大浪费,于是我们想到用单字符或数字来对语句加以区分,只需要检索或存储其关键信息即可。通过观察,程序五条语句的首字母各不相同,我们可以将其做为区分标识,但是由于变量名又是小写的字母,所以我们需要对语句的第二个字符做一个判断,如果是’=’,则语句为赋值语句,第一个字母为变量名,否则即为其他语句。

这样输入信息就处理好了,接下来是如何存储。程序运行的固定配额、程序数以及每条语句运行时间很简单,我们只需分别用int型的q, num, t[5]存储,由于题目中的变量是多个程序共有,我们也可以用int var[maxn]方便的存储各个变量的值。最后就是‘程序’的存储,明显的有两种选择,建立规则将信息处理后再存储,或者直接存储使用时再处理,后者显然很蠢,但是菜鸟还是脑子一抽就开了个char型三维数组存下来了(哎,还是因为前面一直纠结于用什么办法接受输入并且如何处理,查了一堆C++函数觉得太烦 了,干脆上万能的getchar(),连处理也不怎么处理了,剔一些空格完事;至于为什么不一开始就用这么省力的方法,就是觉得这样做好low,而且用了这么久还是对scanf的读入规则还是稀里糊涂,对到底哪些地方需要添加(几个)getchar()接收缓冲区的换行和空白符不怎么清楚,下来一定要好好学习整理一下)

最后就是程序的主体,不过是简单的翻译,有了stl实现了双端队列编写起来就很简单。需要一提的是,一般模拟题不可或缺的状态参量的定义,对应到本题就是index[maxn]blocked分别记录每个程序运行到第几句(相当于真实的PC指针)以及是否处于独占变量状态(注意,题目对这一问题做了简化,即便是一个程序独占了变量,其他程序还是可以对变量进行修改的,但是本菜鸟却以为这一简化反到造成了题目理解的一些障碍)。

最后需要注意的一点就是,每次执行完一个样例后需要恢复到初始状态,即所有相关变量内容的归零,菜鸟常常这里忘记了造成后面灾难性的调试,这次也不例外。一个比较好的解决办法是将相关语句提取出来单独定义一个init()函数,每次run之前调用一下恢复状态,这样程序维护起来也方便。希望以后能慢慢养成这个习惯吧。还有一些标志符特殊值的细节问题,以后再一一总结吧。


ps:菜鸟深知自己的变量命名水平实在捉急,请大神勿喷。

#include<stdio.h>
#include<queue>
#include<iostream>
#include<string.h>
#define maxn 30
using namespace std;

char program[maxn][maxn][maxn];
int q, t[5], var[maxn], num;

int value(char* integer)
{
	int i = 0, outcome = 0;
	while (integer[i] != '\0')
	{
		outcome *= 10;
		outcome += integer[i] - '0';
		i++;
	}
	return outcome;
}

void run()
{
	deque<int> q1, q2;
	for (int i = 0; i < num; i++)
		q1.push_back(i);
	memset(var, 0, sizeof(var));
	int index[maxn] = { 0 },blocked = 0; // 状态参量,index为pc指针,blocked为是否搜定
	while (!q1.empty())
	{
		int temp = q1.front(), r = q, finished = 0;
		q1.pop_front();
		while (r > 0 && !finished)
		{
			char c = program[temp][index[temp]][0];
			if (program[temp][index[temp]][1] != '=')
				switch (c)
				{
				case 'p':
					printf("%d: %d\n", temp + 1, var[program[temp][index[temp]][5] - 'a']);
					r -= t[1];
					index[temp]++;
					break;

				case 'l':
					if (blocked)
					{
						q2.push_back(temp);
						r = -10000000;//特殊值用于后面是否入队判断,注意和正常可能取值区分!!-1也是正常的
					}
					else
					{
						blocked = 1;
						r -= t[2];
						index[temp]++;
					}
					break;

				case 'u':
					blocked = 0;
					if (!q2.empty())
					{
						int p = q2.front();
						q2.pop_front();
						q1.push_front(p);
					}
					r -= t[3];
					index[temp]++;
					break;

				case 'e':
					r = 0;
					finished = 1;
					break;
				}
			else
			{
				var[c - 'a'] = value(program[temp][index[temp]]+2);
				r -= t[0];
				index[temp]++;
			}	
		}
		if (!finished && r!=-10000000) q1.push_back(temp);
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &num);
		for(int i = 0; i < 5; i++)
			scanf("%d", &t[i]);
		scanf("%d", &q);
		getchar();
		for (int i = 0; i < num; i++)
		{
			char temp[maxn];
			int j = 0;
			while (1)
			{
				char c;
				int k = 0;
				while ((c = getchar()) != '\n')
					temp[k++] = c;
				temp[k] = '\0';
				if (strcmp(temp,"end") == 0)
				{
					strcpy(program[i][j], temp);
					break;
				}
				int p1 = -1, p2 = 0;
				while (temp[++p1] != '\0')
					if (temp[p1] != ' ')
						program[i][j][p2++] = temp[p1];
				program[i][j][p2] = '\0';
				j++;
			}
		}
		run();
		if(T) puts("");
	}
}

下面附上刘汝佳大神的代码

// UVa210 Concurrency Simulator
// Rujia Liu
#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cctype>
using namespace std;

const int maxn = 1000;

deque<int> readyQ;
queue<int> blockQ;
int n, quantum, c[5], var[26], ip[maxn]; // ip[pid]是程序pid的当前行号。所有程序都存在prog数组,更类似真实的情况,代码也更短
bool locked;
char prog[maxn][10];

void run(int pid) {
  int q = quantum;
  while(q > 0) {
    char *p = prog[ip[pid]];
    switch(p[2]) {
      case '=':
        var[p[0] - 'a'] = isdigit(p[5]) ? (p[4] - '0') * 10 + p[5] - '0' : p[4] - '0';
        q -= c[0];
        break;
      case 'i': // print
        printf("%d: %d\n", pid+1, var[p[6] - 'a']);
        q -= c[1];
        break;
      case 'c': // lock
        if(locked) { blockQ.push(pid); return; }
        locked = true;
        q -= c[2];
        break;
      case 'l': // unlock
        locked = false;
        if(!blockQ.empty()) {
          int pid2 = blockQ.front(); blockQ.pop();
          readyQ.push_front(pid2);
        }
        q -= c[3];
        break;
      case 'd': // end
        return;
    }
    ip[pid]++;
  }
  readyQ.push_back(pid);
}

int main() {
  int T;
  scanf("%d", &T);
  while(T--) {
    scanf("%d %d %d %d %d %d %d\n", &n, &c[0], &c[1], &c[2], &c[3], &c[4], &quantum);
    memset(var, 0, sizeof(var));

    int line = 0;
    for(int i = 0; i < n; i++) {
      fgets(prog[line++], maxn, stdin);
      ip[i] = line - 1;
      while(prog[line - 1][2] != 'd')
        fgets(prog[line++], maxn, stdin);
      readyQ.push_back(i);
    }

    locked = false;
    while(!readyQ.empty()) {
      int pid = readyQ.front(); readyQ.pop_front();
      run(pid);
    }
    if(T) printf("\n");
  }
  return 0;
}

lrj原来是用fgets来处理输入的,而且连空格都不去除,直接默认已知空格在哪些位置会出现,并用第三个字符来标识五种语句。


最后附上我事后查阅的一些资料

  1. scanf 无法读入空格
    https://blog.csdn.net/beyondlpf/article/details/7358066
  2. 处理格式化输入函数scanf遇空格停止问题
    https://blog.csdn.net/louyijie/article/details/53364447
    https://blog.csdn.net/zhang_kang/article/details/53104259
  3. strcmp函数实现及分析
    https://blog.csdn.net/wgenek/article/details/7257435
  4. c++读取字符串的几种方法
    https://blog.csdn.net/m0_38103546/article/details/79250012
  5. 【日常学习】【双端队列】 Uva - 210 Concurrency Simulator题解
    https://blog.csdn.net/ametake/article/details/43926021

最后一篇博文,该博主对双端队列问题做了详细的总结,代码部分听过某一老师讲解,有较详细注释,可以参考。


ps:程序变量的命名还是重要啊,提交代码过程中WA了一个compilation error,查看详细信息后发现能报WA这个错的我也是人才一个。。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

并行程序模拟(ACM/ICPC World Finals 1991) 的相关文章

  • day37 445 数字反转 (字符串处理、模拟)

    445 数字反转 给定一个整数 请将该数各个位上数字反转得到一个新数 新数也应满足整数的常见形式 即除非给定的原数为零 否则反转后得到的新数的最高位数字不应为零 输入格式 输入共1行 1个整数N 输出格式 输出共1行 1个整数表示反转后的新
  • 模拟CMOS集成电路设计中的电流基准源及用Cadence Virtuoso IC617设计并仿真有关电路

    前言 本文为我自己的学习笔记 属于Cadence Virtuoso系列的进阶部分 采用的软件版本是Cadence Virtuoso IC617 其他文章请点击上方 看我制作的Cadence Virtuoso专栏内容 在前面的文章中 记录了电
  • Basic Level 1010 一元多项式求导 (25分)

    题目 设计函数求一元多项式的导数 注 x n x n xn n为整数 的一阶导数为 n x n
  • CCF-CSP201903-4-消息传递接口

    首先应当思考的是如何对输入数据进行存储 通过样例输入可以看出 每一个进程执行的操作数量都是不定的 因此可以采用 vectorg N 进行存储 其中g i 表示i号进程应执行操作 也可以采用queueq N 进行存储q i 表示i号进程应执行
  • NTSC和PAL制同步信号模拟输出

    NTSC和PAL制同步信号模拟输出 原由 由于我想输出一个NTSC制和PAL制的同步黑场 只需要输出同步信号 之后输出rgb信号给ADV 7123 后输出到显示屏 下面是我的心路历程和知识总结 一 了解NTSC和PAL PAL 电视标准 每
  • Abaqus打开失败FLEXnet Licensing error:-15,10. System Error: 10061 “WinSock: Connection refused“

    好久没用电脑上的abaqus 今天一点启动就出现如下问题 Cannot connect to license server system The license server manager lmgrd has not been start
  • Advanced Leve 1005 Spell It Right (20 point(s))

    Theme Given a non negative integer N your task is to compute the sum of all the digits of N and output every digit of th
  • 紫书《算法竞赛入门经典》

    紫书 算法竞赛入门经典 题目一览 第3章 数组和字符串 例题 UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 340 Master Mind Hints UVA 158
  • Basic Level 1012 数字分类 (20分)

    题目 给定一系列正整数 请按要求对数字进行分类 并输出以下 5 个数字 A 1 A 1 A1 能被 5 整除的数字中所有偶数的和 A 2
  • 模拟get和post请求

    一 模拟请求 浏览器及工具模拟 http请求有很多种 常用的请求方式有两种 get请求和post请求 今天先介绍浏览器以及工具模拟请求 下次会介绍代码模拟 1 get请求格式 url param1 value1 param2 value2
  • River Jumping【贪心+模拟】

    题目链接 我们可以贪心的从前往后 每次选最接近的且满足条件的这样的贪心 然后从后往前的时候 就是直接用倒着一个个判断是否合法即可 include
  • Business Cycle 【UVALive - 7501】【二分答案+思维处理】

    题目链接 14年的EC 银牌题 但是现在的大牛们进步神速 估计如今已经是道铜牌题了 具体我们先讲一下题意 一个长度为N的自环圈 每个点 1 N 上有自己对应的权值 可能为负数 我们用一个初始值进入这个环 每次走到一个节点的时候会加上这个节点
  • L1-046 整除光棍

    这里所谓的 光棍 并不是指单身汪啦 说的是全部由1组成的数字 比如1 11 111 1111等 传说任何一个光棍都能被一个不以5结尾的奇数整除 比如 111111就可以被13整除 现在 你的程序要读入一个整数x 这个整数一定是奇数并且不以5
  • [leetcode] 球会落何处 模拟

    给出一个矩阵 里面的值为 1 or 1 1的时候是从左上到右下 1的时候是从左下到右上 当一个球从上方x 0 lt x lt m 放入之后 从哪个出口掉落还是无法从出口掉落 能通过的情况为 即某条线为 其左边的线也是 箭头所指为当前斜线 即
  • 如何用硬币模拟1/3的概率,以及任意概率?

    突然想起一个挺有意思的事 如何用硬币模拟1 3的概率 甚至任意概率 之前和朋友偶然间谈到如何用硬币模拟任何概率 当时以为是不可能的 因为硬币有两面 模拟的结果底数一定是2 n 今天又回顾了某个经典的条件概率问题 突然想到用硬币模拟任意概率是
  • 猜数字小游戏(JAVA)

    猜数字小游戏 题目描述 代码 运行效果 新增功能 思路 代码 运行效果 题目描述 猜数字 又称 Bulls and Cows 是一种古老的的密码破译类益智类小游戏 起源于20世纪中期 一般由两个人或多人玩 也可以由一个人和电脑玩 通常由两个
  • 2019年第十届蓝桥杯国赛B组试题G-排列数-next_permutation枚举,模拟

    在一个排列中 一个折点是指排列中的一个元素 它同时小于两边的元素 或者同时大于两边的元素 对于一个 1 n 的排列 如果可以将这个排列中包含 t个折点 则它称为一个 t 1 单调序列 例如 排列 1 4 2 3 是一个 3 单调序列 其中
  • “字符串的展开”【题解】

    字符串的展开 的题目 题目 题目描述 在初赛普及组的 阅读程序写结果 的问题中 我们曾给出一个字符串展开的例子 如果在输入的字符串中 含有类似于 d h 或者 4 8 的字串 我们就把它当作一种简写 输出时 用连续递增的字母或数字串替代其中
  • VMware 中搭建 SylixOS 环境

    1 制作 x86 平台 U 盘启动盘 详细步骤见 RealEvo IDE 使用手册 第八章 制作成功后插入 U 盘 2 创建 VMware 虚拟机设备 打开 VMware 这里使用版本为 15 5 6 点击 创建新的虚拟机 按如下步骤创建虚
  • “挖矿”【题解】

    题目 题目描述 有N名矿工在挖矿 工厂预先给第i名矿工支付了M i 元工资 他每挖一吨矿需要消费K i 元 如果他手头余下的钱不足K i 元 他就停止挖矿 他每挖一吨矿 工厂会立即奖励他2元钱 奖励的钱也可以用 于挖矿的消费 给出矿工的信息

随机推荐

  • 测试磁盘寻道时间

    分析性能时 文件系统读取速度不定 主要因为时间不仅花在读取上 还花在磁盘旋转和寻道上 写了一段代码测试这个的时间 一般普通硬盘是10ms左右 有两个函数 第一个函数是生成50G数据 第二个函数是测试 package WebGis Tile
  • OPTICS 点云聚类算法 (附python代码)

    OPTICS Ordering Points To Identify the Clustering Structure 和DBSCAN Density Based Spatial Clustering of Applications wit
  • QObject::connect: Cannot queue arguments of type ‘XXX‘

    1 开发环境 Win10 64bit Qt5 4 2 64bit 2 错误描述 在不同线程之间通过信号 槽来传递自定义数据类型QList
  • jmeter基本教程

    目录 1 简述 2 下载安装 3 基础设置 Jmeter的语言切换 修改Jmeter默认编码为utf 8解决控制台乱码 4 编写项目测试脚本 4 1 添加线程组 4 2 添加测试接口 4 3 添加察看结果树 4 4 添加用户自定义变量 4
  • QTHelprModule.dll 是什么

    QTHelperModule dll 是一个 Windows 平台上的动态链接库 DLL 文件 它通常是某些软件的一部分 用于执行特定的功能和服务 该文件可能包含代码 资源和数据 可以被其他应用程序调用 以实现不同的功能 如果您的系统出现了
  • 物联网:用python调入机器学习分析物联网数据入侵检测模块

    要使用Python调用机器学习分析物联网数据入侵检测模块 您需要以下步骤 安装Python和相关的机器学习库 如scikit learn pandas numpy等 您可以使用pip命令来安装这些库 准备输入数据 这些数据可以是来自物联网设
  • CentOS7 使用minikube 搭建kubernetes 学习环境

    Windows 10 系统 VirtualBox 6 0 x CentOS7启动在虚拟机上 先要安装docker 官网 https docs docker com engine install 有guide 一步步下来很简单 不多说了 按照
  • Python 之 格式化输出

    欢迎大家扫码关注我的微信公众号 Python 格式化输出 目录 一 为何需要进行格式化输出 二 格式化输出的几种方式 2 1 使用 进行格式化 2 1 1 字符串的格式化 2 1 2 浮点数的格式化 2 2 使用 format 进行格式化
  • DFRobot新推出一款适合短时间环境数据记录的Gravity 串口数据记录器

    著名开源硬件商DFRobot新推出一款Gravity 串口数据记录器 适用于做科学记录或短时间环境数据记录 Gravity 串口数据记录器产品特性 1 Gravity 串口数据记录器相比 MicroSD卡 读卡器模块存储数据 可以更方便的存
  • Gradle编译失败问题汇总

    Gradle编译失败问题汇总 问题1 Could not resolve org springframework boot spring boot gradle plugin 3 0 0 A problem occurred configu
  • canonical raft源码编译

    canonical raft源码编译 一 下载源码 二 安装环境 三 编译 四 问题报错 五 总结 一 下载源码 https codeload github com canonical raft tar gz refs tags v0 11
  • 自建代码托管平台 Gitlab 的使用说明(二)常用命令

    一 运维管理排查 查看版本 cat opt gitlab embedded service gitlab rails VERSION 检查gitlab gitlab rake gitlab check SANITIZE true trace
  • opencv 学习代码整理

    1 load image import cv2 import numpy as npfrom matplotlib import pyplot as plt img cv2 imread watch jpg cv2 IMREAD GRAYS
  • three.js实现vr全景图(vue)

    方法 可以利用Threejs中的立方体或者球体实现全景图功能 把立方体或球体当成天空盒子 将无缝衔接的图片贴上 看起来就像在一个场景中 相机一般放置在中央 three js中文网 1 立方体实现 立方体6个面要贴上6个方向的图片 这6个图片
  • 【前端八股文】vue系列:vue的优点和特点、生命周期、ref、$nextTick

    文章目录 vue的优点和特点 双向数据绑定 虚拟DOM 组件化 生命周期 十个阶段 相关功能 题外话 数据请求在created和mouted的区别 ref nextTick 参考 本系列目录 前端八股文 目录总结 是以 代码随想录 八股文为
  • cut、tee、split、xargs、bc命令

    http sss721 blog 163 com blog static 10170119200992811123802 一 cut命令 cut 主要的用途在于将一行里面的数据进行分解 最常使用在分析一些数据或文字数据的时候 这是因为有时候
  • public、private、protected、internal的区别

    public private protected internal和protected internal都是C 中的访问控制修饰符 用于修饰类或者成员的可访问性级别 public 表示同一程序集中的任何其他代码或者引用该程序集中的其它程序集
  • WiFi station模式:wpa_supplicant 工具 wpa_cli 使用

    首先需要启动wpa supplicant 指定wlan0的路径 wpa supplicant d Dnl80211 iwlan0 c etc config wifi wpa supplicant conf 搜索附近网络功能 no ok wp
  • 怎么在edge浏览器下载扩展(插件)

    1 点击浏览器右上角的三个点 找到扩展点进去 2 如果安装过插件 此刻右上角的扩展按钮会弹出安装好的插件信息 如下图 点击 打开Microsoft Edge 加载项 进入微软edge扩展商店 3 没有安装过插件的 会跳到管理扩展界面 如下图
  • 并行程序模拟(ACM/ICPC World Finals 1991)

    附上题目连接 concurrency simulator 本题为紫书数据结构基础篇第一道例题 是一道考察双端队列的模拟题 由于使用了STL 题目的难度和编程量大大降了下来 不过本菜鸟还是花了三个半小时才拿下了这道题 30msAC 可想见代码