题目大意:
在系统学中,Petri nets的一种特殊情况经常被纳入考虑范围,这种特殊情况被称为Synchrograph。Synchrograph是一个有向图,每条弧都有一个非负整数权。一个点,如果所有指向它的边都是正数(也就是大于0),这个点就称之为“可燃点”。
对Synchrograph的操作是一轮一轮进行的。在每一轮中,操作者都会随机的选一个“可燃点”进行“燃烧”。所谓燃烧就是:所有指向这个点的弧权都减1,所有从这个点指出去的弧都加1。每一轮之后,“可燃点”根据新的弧权被更新,然后下一轮操作继续进行。
如果存在一个操作序列,使得某个点变成可燃点,那么这个点就称之为“潜在活动点”。
如果经过任意一个操作序列之后,某个点依然是“潜在活动点”,这个点就称之为“活动点”。
分析:
看懂样例证明你看懂了题意,而我却看了半天…
我们考虑非活动点与活动点之间的关系。
如果一个点
v
的前驱中有非活动点
如果一个点的前驱全为活动点,那么这个点肯定为活动点。因为前驱到它的边总是递增的,因此无论怎样它都可以变成潜在活动点。
如果存在一个边权为 0 的环,那么环上的点一定为非活动点,这个结论很显然。
AC code:
#include <cstdio>
#include <cstring>
#include <queue>
#define ONLINE_JUDGE
using namespace std;
const int MAXN = 1009;
const int MAXM = 50009;
int n, m;
struct Dgraph
{
int size;
int head[MAXN];
int to[MAXM];
int w[MAXM];
int ne[MAXM];
Dgraph(){size = 1;}
void add_edge(int u, int v, int wi)
{
to[size] = v, ne[size] = head[u], w[size] = wi, head[u] = size++;
}
}G, G2;
int deg[MAXN];
queue<int> q;
int ans[MAXN];
int read()
{
char c;
int x = 0, f = 1;
while(((c=getchar()) < '0' || c > '9') && c != '-');
if(c == '-') f = -1;
else x = c-'0';
while((c=getchar()) >= '0' && c <= '9') x = x*10+c-'0';
return x*f;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("sgu219.in", "r", stdin);
freopen("sgu219.out", "w", stdout);
#endif
n = read(), m = read();
for(int i = 1; i <= m; ++i)
{
int u = read(), v = read(), w = read();
G.add_edge(u, v, w), deg[v] += w==0;
}
for(int i = 1; i <= n; ++i)
if(!deg[i]) q.push(i);
while(!q.empty())
{
int u = q.front();q.pop();
for(int i = G.head[u]; i; i = G.ne[i])
if(!G.w[i])
if(!(--deg[G.to[i]]))
q.push(G.to[i]);
}
for(int i = 1; i <= n; ++i) ans[i] = 1;
for(int i = 1; i <= n; ++i)
if(deg[i]) ans[i] = 0, q.push(i);
while(!q.empty())
{
int u = q.front();q.pop();
for(int i = G.head[u]; i; i = G.ne[i])
if(ans[G.to[i]])
ans[G.to[i]] = 0, q.push(G.to[i]);
}
for(int i = 1; i <= n; ++i)
printf("%d\n", ans[i]);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}