UVA - 804 Petri Net Simulation

/*
题目链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=745

小白书上的说明:
本题有一定实际意义,理解题意后编码并不复杂,建议读者一试
(然而这题,就是题目不太好完全理解,我最初先看了几次题目,又对照着别人题解上的代码,再看了几次题目,才差不多弄懂了题目意思)
*/


/*
  法一:
  参考了:http://blog.csdn.net/chy20142109/article/details/50756318
  //附带说一下,从这个blog里又get到了一些新技能和神操作...虽然原理也就是 #define 的用法而已,但是...这个博主的头文件和 define 的那些模板真的不错~
*/

#include <iostream>
#include <cstdio>
#include <cstring>
#define Clean(x, y) memset(x, y, sizeof(x))
#define rep(i, j, k) for (int i = j; i <= k; i++)
#define Rrep(i, j, k) for (int i = j; i >= k; i--)
using namespace std;

int np, nt, nf, tp; //nf是指定的步骤数,tp::temp表示一个临时的变量 
const int N = 105;
int num[N]; //对应每个 place 当前含有 token 的数量
int input[N][N], output[N][N];
// 每个 transition 对应的输入、输出端
// input[i][j] 表示第 i 个 transition 的第 j 个输入端的编号
int Inum[N][N];
//有可能一个place发出多条路线指向一个transition,记录每个place发出的路线。
// Inum[i][j]表示第i个transition的第j个输入端指向第i个transition的路线数 

int find (int x, int k)
{
	rep(i, 1, input[x][0]) if ( input[x][i] == k) return i;
	return -1;
}
//找第 x个 transition 的输入端中有没有值为 k 的,如果有,返回为 k 的输入端,在第 x 个 transition 的所有输入端中的编号;没找到则返回 -1 

void init()
{
	Clean(num, 0);
	Clean(input, 0);
	Clean(output, 0);
	Clean(Inum, 0);
	
	rep(i, 1, np) scanf("%d", num + i);
	scanf("%d", &nt);
	rep(i, 1, nt)
	{
		while (scanf("%d", &tp), tp)
		{
			if ( tp < 0 )
			{
				int p = find(i, -tp);
				if ( p != -1 ) Inum[i][p]++;
				else
				{
					input[i][++input[i][0]] = -tp;
					Inum[i][input[i][0]] = 1;
				}
				/*
				 这里顺带再啰嗦一句,自己想了一段时间的一个细节
				 因为每次调用 find 函数找不到时,都要先 ++input[i][0]
				 所以,最后 input[i][0] 会变成 transition 的输入端的总数,如果有输入端输入的 token 数相同时,那就累加到 Inum 数组上,用来记录 "这一种输入端"有几个,其实也还是归类,以便于记录的思想 
				*/ 
			}
			else output[i][ ++output[i][0] ] = tp;
		}
	}
	scanf("%d", &nf);
}

bool check (int x)
{
	rep(i, 1, input[x][0])
	if ( num [ input[x][i] ] < Inum[x][i] ) return false;
	return true;
}

int main()
{
	int kase = 0;
	while ( cin >> np && np != 0)
	{
		init();
		int step = 0;
		bool can = true;
		// 如果存在可变迁的点,则一直变迁,直到达到指定次数 
			while (can && step < nf)
			{
				can = false;
				rep(k, 1, nt)
				{
					if ( step < nf && check(k) ) // 检查 j 是否可以变迁
					{
						can = true;
						step++;
						rep(i, 1, input[k][0]) num[ input[k][i] ] -= Inum[k][i];
						rep(i, 1, output[k][0]) num[ output[k][i] ]++;
						//每个可以变迁的点,输入和输出端同时变化 
					} 
				}
			}
			printf("Case %d: ",++kase);
        	if ( step == nf ) printf("still live after %d transitions\n",nf); //到达指定变迁次数
       		else printf("dead after %d transitions\n",step);  //中途结束
        	printf("Places with tokens:"); 
        	rep(i,1,np)
            if (num[i]) printf(" %d (%d)",i,num[i]);
        	puts("");
        	puts("");
	}
	return 0;
}

/*
查阅的其他资料整理:
http://www.cnblogs.com/woaiheniunai/p/6394672.html

http://blog.csdn.net/wcr1996/article/details/44532065
//这种用结构体来处理的方式,写法更简洁,且更容易理解

http://blog.csdn.net/c21c21/article/details/44701509
//这种用 vector 来处理的方法,也比我模仿重敲的那份代码容易理解一些,而且我觉得这个解法思路的逻辑更加清晰

http://blog.csdn.net/weizhuwyzc000/article/details/44100277
//这个题解和我贴上的代码的思路比较类似,比较不同的是,它用了map,并且调用了map里的 count 函数,STL的使用,简化了初始化时的代码量
*/


posted @ 2017-10-29 22:40  mofushaohua  阅读(359)  评论(0编辑  收藏  举报