LightOJ 1074 Extended Traffic(spfa+dfs标记负环上的点)

题目链接:https://cn.vjudge.net/contest/189021#problem/O

题目大意:有n个站点,每个站点都有一个busyness,从站点A到站点B的花费为(busyness of B  -  busyness of A)^3。给出个站点间的连通关系(单向),有q次询问,每次询问站点1到x(1<=x<=n)的最小花费,若x点无法到达或者花费小于3则输出‘?’。

解题思路:还是最短路问题,但是图中有负环的存在,所以要判断负环,每次发现负环上的点(qcnt[i]>=n)就用dfs标记该负环上所有的点(负环上的点花费肯定小于3),可以使用spfa来解决。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=2e2+5;
 8 const int INF=0x3f3f3f3f;
 9 
10 int n;
11 int dis[N],busy[N],qcnt[N],cost[N][N];
12 bool vis[N],cir[N];
13 
14 //计算j,k两点间的收费 
15 int cal_amt(int j,int i){
16     return (busy[i]-busy[j])*(busy[i]-busy[j])*(busy[i]-busy[j]);
17 }
18 //标记所有x点能到达的点 
19 void dfs(int x){
20     cir[x]=true;
21     for(int i=1;i<=n;i++){
22         if(cost[x][i]==1&&!cir[i])
23             dfs(i);
24     }
25 }
26 
27 bool spfa(int s){
28     memset(dis,0x3f,sizeof(dis));
29     memset(vis,false,sizeof(vis));
30     memset(qcnt,0,sizeof(qcnt));
31     dis[s]=0;
32     queue<int>q;
33     q.push(s);
34     while(!q.empty()){
35         int k=q.front();
36         q.pop();
37         vis[k]=false;
38         for(int i=1;i<=n;i++){
39             //跳过负环上的点
40             if(i==k||cost[k][i]==-1||cir[i])
41                 continue;
42             if(dis[k]+cal_amt(k,i)<dis[i]){
43                 dis[i]=dis[k]+cal_amt(k,i);
44                 if(!vis[i]){
45                     q.push(i);
46                     qcnt[i]++;
47                     //若存在负环,则dfs标记所有负环上的可达点
48                     if(qcnt[i]>=n)
49                         dfs(i);
50                     vis[i]=true;
51                 }
52             }
53         }
54     }
55 }
56 
57 int main(){
58     int t,cas=0;
59     scanf("%d",&t);
60     while(t--){
61         memset(cost,-1,sizeof(cost));
62         memset(cir,false,sizeof(cir));
63         scanf("%d",&n);
64         for(int i=1;i<=n;i++){
65             scanf("%d",&busy[i]);
66         }
67         int m;
68         scanf("%d",&m);
69         for(int i=1;i<=m;i++){
70             int a,b;
71             scanf("%d%d",&a,&b);
72             cost[a][b]=1;
73         }
74         int q;
75         scanf("%d",&q);
76         spfa(1);
77         printf("Case %d:
",++cas);
78         for(int i=1;i<=q;i++){
79             int des;
80             scanf("%d",&des);
81             //若该点在负环上、或者无法到达、或者收费小于3输出'?' 
82             if(cir[des]||dis[des]==INF||dis[des]<3)
83                 puts("?");
84             else
85                 printf("%d
",dis[des]);
86         }
87     }
88     return 0;
89 }
原文地址:https://www.cnblogs.com/fu3638/p/7881369.html