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的使用,简化了初始化时的代码量 */