Light oj 1074 spfa标记负环节点
题意:
对图中的N点,给出q个询问,输出起点到询问点之间的最短路.
若不可达或最短路小于3,输出 ?
思路:如果图中存在负环,那么若询问负环中的点,都需要输出'?'.
所以在spfa中要增加一个环节,当判断到存在负环时,需要用dfs标记出当前负环上的所有点.
#include<cstdio> #include<iostream> #include<queue> #include<cstring> #include<cmath> using namespace std; #define ll long long #define pb push_back #define fi first #define se second #define pii pair<int,int> #define mp make_pair const int N = 3333; const int INF = 1E9+3; struct edge{ int to,cost; }; vector<edge> V[N]; int b[N],d[N]; int vis[N]; int circle[N]; int num[N]; int n; int m; void dfs(int t){ circle[t]=1; for(int i=0;i<V[t].size();++i){ if(circle [ V[t][i].to ] ==0){ dfs(V[t][i].to); } } } void spfa(){ memset(vis,0,sizeof(vis)); memset(circle,0,sizeof(circle)); for(int i=1;i<=n;++i)d[i]=INF; d[1]=0; queue<int>Q; Q.push(1); vis[1]=1; num[1]=1; while(!Q.empty()){ int v = Q.front();Q.pop(); vis[v]=0; for(int i=0;i<V[v].size();++i){ int u =V[v][i].to;int val =V[v][i].cost; if(circle[u])continue; if(d[u] > d[v]+val){ d[u]=d[v]+val; if(vis[u]==0){ vis[u]=1; Q.push(u); num[u]++; if(num[u]>n)dfs(u); } } } } } int main(){ int t; cin>>t; int cnt =1; while(t--){ scanf("%d",&n); for(int i=1;i<=n;++i)scanf("%d",b+i); for(int i=1;i<=n;++i)V[i].clear(); scanf("%d",&m); int u,v; while(m--){ scanf("%d %d",&u,&v); int d = b[v]-b[u]; V[u].pb( edge{ v, d*d*d } ); } int q; cin>>q; printf("Case %d:\n",cnt++); spfa(); while(q--){ int x; scanf("%d",&x); if(circle[x] || d[x]==INF || d[x]<3){ printf("?\n",d[x]); } else printf("%d\n",d[x]); } } return 0; }