题目链接:https://vjudge.net/problem/LightOJ-1074
最短路问题,而且会有负环,需要把负环上的点都找出来,用spfa+dfs
用stack实现的spfa,比起用queue实现的快了有一倍(有负环情况下stack更快)
这题卡了很久,因为一个莫名的地方(代码里用注释标出来了),心累。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N=200+20;
const int inf=0x3f3f3f3f;
int g[N][N];
bool vis[N],r[N],g0[N][N];
int d[N],c[N];
int t,n,m,qu;
void dfs(int u) //寻找负环并标记
{
r[u]=true;
for(int i=1;i<=n;i++)
if(g0[u][i]&&!r[i])
dfs(i);
}
int main()
{
scanf("%d",&t);
int kase=0;
while(t--)
{
int num[N],cnt[N],a,b;
memset(g,inf,sizeof(g));
memset(g0,false,sizeof(g0));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
g[a][b]=(num[b]-num[a])*(num[b]-num[a])*(num[b]-num[a]);
g0[a][b]=true;
}
stack<int> q;
q.push(1);
memset(d,inf,sizeof(d));
memset(vis,false,sizeof(vis));
memset(r,false,sizeof(r));
memset(cnt,0,sizeof(cnt));
d[1]=0;vis[1]=true;cnt[1]=1;
while(!q.empty()) //spfa
{
int u=q.top();
q.pop();vis[u]=false;
for(int i=1;i<=n;i++)
if(!r[i]&&g0[u][i]&&d[i]>d[u]+g[u][i]) //必须先判断g0[u][i]是否联通???不然WA!!!
{
d[i]=d[u]+g[u][i];
if(!vis[i])
{
q.push(i);
vis[i]=true;
cnt[i]++;
if(cnt[i]>n)
dfs(i);
}
}
}
scanf("%d",&qu);
for(int i=0;i<qu;i++)
scanf("%d",&c[i]);
printf("Case %d:\n",++kase);
for(int i=0;i<qu;i++)
{
a=c[i];
if(d[a]<3||d[a]>=inf||r[a]) printf("?\n");
else printf("%d\n",d[a]);
}
}
return 0;
}