LightOJ 1074 - Extended Traffic 【SPFA】(经典)

题目大意:
有n个城市,每一个城市有一个拥挤度Ai,从一个城市I到另一个城市J的时间为:(A(v)-A(u))^3。问从第一个城市到达第k个城市所花的时间,如果不能到达,或者时间小于3输出?否则输出所花的时间。

解题分析:

很明显,此题路段的权值可能为负,所以我们就不能用Dijkstra算法求最短路了。需要注意的是,当点存在负环的时候,就要将负环所能够到达的所有点全部标记,从起点到这些点的最短路是不存在的(因为假设如果存在最短路,那么只要途中在负环上多走几遍,那么重新算得的时间一定会变少,所以不存在最短路)。所以,总的来说,对于本题,对那些负环能够到达的点,和从起点无法到达的点,和时间小于3的点,全部输出“?”,其他满足条件的直接输出最短时间就行。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 
  8 
  9 const int MAXN=220;
 10 const int INF =0x3f3f3f3f;
 11 
 12 struct Edge{
 13     int to;
 14     int next;
 15     int val;
 16 }edge[MAXN*MAXN];
 17 
 18 int res,n;
 19 int head[MAXN];
 20 bool vis[MAXN];      //记录该点是否在队列内
 21 bool cir[MAXN];      //记录该点是否为负环上的点
 22 int a[MAXN],dist[MAXN],cnt[MAXN];   //cnt[]数组记录该数在队列中出现的次数
 23 
 24 void dfs(int u){     //将该负环所能够达到的所有点全部标记
 25     cir[u]=true;
 26     for(int i=head[u];i!=-1;i=edge[i].next){
 27         int v=edge[i].to;
 28         if(!cir[v])dfs(v);
 29     }
 30 }
 31 
 32 void init(){
 33     memset(head,-1,sizeof(head));
 34     res=0;
 35 }
 36 
 37 void add(int u,int v,int w){
 38     edge[res].to=v,edge[res].val=w;
 39     edge[res].next=head[u];
 40     head[u]=res++;
 41 }
 42 
 43 void SPFA(int st){
 44     memset(vis,false,sizeof(vis));
 45     memset(cir,false,sizeof(cir));
 46     memset(cnt,0,sizeof(cnt));
 47     for(int i=1;i<=n;i++)
 48         dist[i]=INF;
 49     dist[st]=0;
 50     queue<int>q;
 51     q.push(st);
 52     cnt[st]=1;
 53     vis[st]=true;
 54     while(!q.empty()){
 55         int u=q.front();
 56         q.pop();
 57         vis[u]=false;   //当该点从队列中pop掉之后,就要清除vis标记 
 58         for(int i=head[u];i!=-1;i=edge[i].next){
 59             int v=edge[i].to;
 60             if(cir[v])continue;  //如果是负环上的点
 61             if(dist[v]>dist[u]+edge[i].val){
 62                 dist[v]=dist[u]+edge[i].val;
 63                 if(!vis[v]){    //如果该点不在队列中
 64                     vis[v]=true;
 65                     q.push(v);
 66                     cnt[v]++;
 67                     if(cnt[v]>n){    //若存在负环,就用dfs将该负环能够达到的所有点标记
 68                         dfs(v);
 69                     }
 70                 }
 71             }
 72         }
 73     }
 74 }
 75 
 76 int main(){
 77     int t;scanf("%d",&t);
 78     int ncase=0;
 79     while(t--){
 80         init();
 81         scanf("%d",&n);
 82         for(int i=1;i<=n;i++)
 83             scanf("%d",&a[i]);
 84         int m;
 85         scanf("%d",&m);
 86         while(m--){
 87             int u,v;
 88             scanf("%d %d",&u,&v);
 89             add(u,v,(a[v]-a[u])*(a[v]-a[u])*(a[v]-a[u]));
 90         }
 91 
 92         SPFA(1);
 93         printf("Case %d:\n",++ncase);
 94         scanf("%d",&m);
 95         while(m--){
 96             int u;scanf("%d",&u);
 97             if(cir[u] || dist[u]<3 || dist[u] == INF)  //如果询问的点能由负环达到、或者到起点的最小受益小于3、或者询问的点不可达
 98                 printf("?\n");
 99             else printf("%d\n",dist[u]);
100         }
101     }
102     return 0;
103 }

猜你喜欢

转载自www.cnblogs.com/-Ackerman/p/11296918.html