题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1074
题意:有n个城市,每一个城市有一个拥挤度ai,从一个城市I到另一个城市J的时间为:(aJ-aI)^3,存在负环。问从第一个城市到达第k个城市所花的时间,如果不能到达,或者时间小于3输出?否则输出所花的时间
只要用spfa判断一下负环然后和负环上点相关联的点都可以实现距离无线小所以如果是关联点标记一下。
如果遇到标记点就没有必要再入队,减少复杂度
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdio>
#include <queue>
using namespace std;
const long long inf = 999999999;
int n , m , q , x , y;
long long val[210] , dis[210];
long long GETS(int x , int y) {
return (val[x] - val[y]) * (val[x] - val[y]) * (val[x] - val[y]);
}
struct TnT {
int u , v , next;
long long w;
}T[40050];
int head[210] , cnt[210] , e;
void init() {
e = 0;
for(int i = 1 ; i <= n ; i++) {
head[i] = -1;
}
}
void add(int u , int v , long long w) {
T[e].v = v;
T[e].w = w;
T[e].next = head[u];
head[u] = e++;
}
bool vis[210] , cir[210];
void dfs(int x) {
cir[x] = true;
for(int i = head[x] ; i != - 1 ; i = T[i].next) {
if(!cir[T[i].v]) {
dfs(T[i].v);
}
}
}
void spfa(int sta) {
memset(vis , false , sizeof(vis));
memset(cnt , 0 , sizeof(cnt));
memset(cir , false , sizeof(cir));
queue<int>q;
q.push(sta);
cnt[sta]++;
vis[sta] = true;
dis[sta] = 0;
while(!q.empty()) {
int m = q.front();
vis[m] = false;
q.pop();
for(int i = head[m] ; i != - 1 ; i = T[i].next) {
int v = T[i].v ;
long long w = T[i].w;
if(cir[v])
continue;
if(dis[v] > dis[m] + w) {
dis[v] = dis[m] + w;
if(!vis[v]) {
cnt[v]++;
vis[v] = true;
q.push(v);
if(cnt[v] > n)
dfs(v);
}
}
}
}
}
int main() {
int t , ans = 0 , gg;
scanf("%d" , &t);
while(t--) {
ans++;
scanf("%d" , &n);
for(int i = 1 ; i <= n ; i++) {
dis[i] = inf;
}
init();
for(int i = 1 ; i <= n ; i++) {
scanf("%lld" , &val[i]);
}
scanf("%d" , &m);
for(int i = 1 ; i <= m ; i++) {
scanf("%d%d" , &x , &y);
add(x , y , GETS(y , x));
}
printf("Case %d:\n" , ans);
scanf("%d" , &q);
spfa(1);
for(int i = 1 ; i <= q ; i++) {
scanf("%d" , &gg);
if(cir[gg] || dis[gg] == inf || dis[gg] < 3) {
printf("?\n");
}
else {
printf("%lld\n" , dis[gg]);
}
}
}
return 0;
}