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