算法竞赛入门经典 习题6-7

本文介绍了一个Petri网的模拟程序,通过定义地方(place)和变迁(transition),模拟了token在网络中的流动过程。程序实现了判断在一系列操作后Petri网是否仍能继续执行的功能。

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

UVa804

Petri Net Simulation

Petri网络由放置token的place和传输token的transition组成,每个transition的输入端连接若干个place,输出端连接若干个place。对于每个transition,当输入place中均有一个可用的token时,会从每个输入place中取出一个token,并向输出place中放入一个token,这个过程称为action。给定一个petri网络,求出若干个action后,petri网络是否还能继续执行action。

有三点需要注意:

  • 执行action的过程中,token会变少,这是petri网络最终停下的一个重要原因
  • 描述transition的输入数据并不是负数在前,正数在后,因为这个我WA了很多次
  • 题目保证选择不同的transition执行action不会对最终结果产生影响,所以写成深搜的形式并不完美,最好还是写成循环
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

struct Transition
{
	map<size_t, size_t> input, output;
	bool fire(vector<size_t> &tokens) const
	{
		for (auto iter = input.begin(); iter != input.end(); iter++)
		{
			if (tokens[iter->first] < iter->second) return false;
		}
		for (auto iter = input.begin(); iter != input.end(); iter++)
		{
			tokens[iter->first] -= iter->second;
		}
		for (auto iter = output.begin(); iter != output.end(); iter++)
		{
			tokens[iter->first] += iter->second;
		}
		return true;
	}
};

class Solution
{
public:
	Solution(const vector<size_t> &tokens, const vector<Transition> &transitions, int nf)
		: transitions(transitions), LeftTokens(tokens), dead(false), FireCounter(0), nf(nf)
	{
		simulation(tokens, 0);
	}
	string result(int cases)
	{
		ostringstream oss;
		oss << "Case " << cases << ": ";
		if (dead) oss << "dead after " << FireCounter;
		else oss << "still live after " << nf;
		oss << " transitions\n";
		oss << "Places with tokens:";
		for (size_t i = 0; i < LeftTokens.size(); i++)
		{
			if (LeftTokens[i] > 0) {
				oss << ' ' << i + 1 << " (" << LeftTokens[i] << ')';
			}
		}
		oss << endl;
		return oss.str();
	}
private:
	vector<Transition> transitions;
	vector<size_t> LeftTokens;
	bool dead;
	int FireCounter, nf;
	void simulation(const vector<size_t> &tokens, int step)
	{
		for (int step = 0; step < nf; step++)
		{
			bool fired = false;
			for (const Transition &transition : transitions)
			{
				if (transition.fire(LeftTokens)) {
					fired = true;
					break;
				}
			}
			if (!fired) {
				FireCounter = step;
				dead = true;
				break;
			}
		}
	}
};

int main()
{
	int cases = 0, np, nt, nf;
	while (cin >> np) {
		if (np == 0) break;
		cases++;
		vector<size_t> tokens;
		size_t token;
		for (int i = 0; i < np; i++)
		{
			cin >> token;
			tokens.push_back(token);
		}
		cin >> nt;
		vector<Transition> transitons;
		for (int i = 0; i < nt; i++)
		{
			transitons.push_back(Transition());
			int place;
			while (cin >> place) {
				if (place < 0) {
					transitons.back().input[static_cast<size_t>(-(place + 1))]++;
				}
				else if (place > 0) {
					transitons.back().output[static_cast<size_t>(place - 1)]++;
				}
				else break;
			}
		}
		cin >> nf;
		Solution solution(tokens, transitons, nf);
		cout << solution.result(cases) << endl;
	}
	return 0;
}
/*
2
1 0
2
-1 2 0
-2 1 0
100
3
3 0 0
3
-1 2 0
-2 -2 3 0
-3 1 0
100
0
*/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值