题目来源:Light OJ 1108 Instant View of Big Bang
题意:求哪些点可以回到过去 首先负环的点是可以的 一直在付欢里转即可 然后那些可以走到负环的点满足
思路:反向建图 这样负环还是不会变的 只不过负环的方向换了下 原来能到负环的点变成了现在负环能到的点 求出负环标记然后广搜负环能到的点再标记
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 1111;
const int maxm = 2222;
const int INF = 999999999;
struct edge
{
int u, v, w;
int next;
edge(){}
edge(int u, int v, int w): u(u), v(v), w(w) {}
}e[maxm];
int first[maxn], cnt;
int d[maxn], sum[maxn];
bool inq[maxn], ok[maxn];
int n, m;
void AddEddge(int u, int v, int w)
{
e[cnt].u = u;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].next = first[u];
first[u] = cnt++;
}
void BFS(int rt)
{
queue <int> Q;
Q.push(rt);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
ok[u] = true;
for(int x = first[u]; x != -1; x = e[x].next)
{
int v = e[x].v;
if(ok[v])
continue;
Q.push(v);
}
}
}
void SPFA()
{
queue <int> Q;
memset(ok, false, sizeof(ok));
memset(inq, false, sizeof(inq));
memset(sum, 0, sizeof(sum));
for(int i = 0; i < n; i++)
{
d[i] = 0;
Q.push(i);
}
while(!Q.empty())
{
int u = Q.front(); Q.pop();
if(ok[u])
continue;
inq[u] = false;
for(int x = first[u]; x != -1; x = e[x].next)
{
int v = e[x].v;
if(d[v] > d[u] + e[x].w)
{
d[v] = d[u] + e[x].w;
if(!inq[v])
{
inq[v] = true;
Q.push(v);
if(++sum[v] > n)
BFS(v);
}
}
}
}
}
int main()
{
int cas = 1;
int T;
scanf("%d", &T);
while(T--)
{
memset(first, -1, sizeof(first));
cnt = 1;
scanf("%d %d", &n, &m);
for(int i = 0; i < m; i++)
{
int u, v, w;
scanf("%d %d %d", &v, &u, &w);//反向建图
AddEddge(u, v, w);
}
SPFA();
printf("Case %d:", cas++);
int flag = 0;
for(int i = 0; i < n; i++)
{
if(ok[i])
{
flag++;
printf(" %d", i);
}
}
if(!flag)
printf(" impossible");
puts("");
}
return 0;
}