原题地址:点击打开链接
题意:让你找出分别从1到n出发,能否到达过去,意思就是能否到达负环。那么负环上的点肯定是都可以的,还有能到达负环的点是可以的,反向建图即可。
找到一个负环上的点后,遍历它所能达到的点。
#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>
#define INF 1<<31-1
using namespace std;
struct Edge
{
int to;
int year;
};
vector<Edge>edge[1010];
bool inQ[1010] ; //标记是否在队列
int dis[1010]; //从源点到该点最早的年份
int in[1010]; //记录顶点入队列的次数
bool ans[1010]; //可以从该点出发到达过去 (负环上的点)
int k=0,n;
void bfs(int s) //找寻所有负圈能到达的点
{
queue<int>Q;
Q.push(s);
ans[s]=true;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int i=0;i<edge[u].size();i++)
{
Edge e=edge[u][i];
int v=e.to;
if(!ans[v])
{
ans[v]=true;
Q.push(v);
}
}
}
}
void spfa(int s)
{
for(int i=0;i<n;i++)
dis[i]=INF;
dis[s]=0;
queue<int>Q;
Q.push(s);
inQ[s]=true;
while(!Q.empty())
{
int u=Q.front();
inQ[u]=false;
Q.pop();
if(ans[u])
continue;
for(int i=0;i<edge[u].size();i++)
{
Edge e=edge[u][i];
if(dis[e.to]>dis[u]+e.year)
{
dis[e.to]=dis[u]+e.year;
if(!inQ[e.to])
{
Q.push(e.to);
inQ[e.to]=true;
if(++in[e.to]>=n)
{
bfs(e.to);
}
}
}
}
}
}
void solve()
{
memset(ans,false,sizeof(ans));
int mark=0;
for(int i=0;i<n;i++)
{
memset(in,0,sizeof(in));
memset(inQ,false,sizeof(inQ));
if(!ans[i])
{
spfa(i);
}
}
printf("Case %d:",++k);
for(int i=0;i<n;i++)
{
if(ans[i])
{
mark=1;
printf(" %d",i);
}
}
if(mark==0)
printf(" impossible");
printf("\n");
}
int main()
{
int t,m,i,u,v,year;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
edge[i].clear();
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&year);
edge[v].push_back((Edge){u,year}); //反向建图
}
solve();
}
return 0;
}
/*
3
3 3
0 1 1000
1 2 15
2 1 -42
4 4
0 1 10
1 2 20
2 3 30
3 0 -60
5 5
0 1 1000
1 2 2
2 3 -20
2 4 -50
3 1 -30
*/