NYOJ-115 城市平乱

                                                     城市平乱

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述

南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市。

他在用这N个部队维护着M个城市的治安,这M个城市分别编号从1到M。

现在,小工军师告诉南将军,第K号城市发生了暴乱,南将军从各个部队都派遣了一个分队沿最近路去往暴乱城市平乱。

现在已知在任意两个城市之间的路行军所需的时间,你作为南将军麾下最厉害的程序员,请你编写一个程序来告诉南将军第一个分队到达叛乱城市所需的时间。

注意,两个城市之间可能不只一条路。

输入
第一行输入一个整数T,表示测试数据的组数。(T<20)
每组测试数据的第一行是四个整数N,M,P,Q(1<=N<=100,N<=M<=1000,M-1<=P<=100000)其中N表示部队数,M表示城市数,P表示城市之间的路的条数,Q表示发生暴乱的城市编号。
随后的一行是N个整数,表示部队所在城市的编号。
再之后的P行,每行有三个正整数,a,b,t(1<=a,b<=M,1<=t<=100),表示a,b之间的路如果行军需要用时为t

数据保证暴乱的城市是可达的。
输出
对于每组测试数据,输出第一支部队到达叛乱城市时的时间。每组输出占一行
样例输入
1
3 8 9 8
1 2 3
1 2 1
2 3 2
1 4 2
2 5 3
3 6 2
4 7 1
5 7 3
5 8 2
6 8 2 
样例输出
4
 

这是一道非常经典的图论最短路问题!试了4种解法(Bellman-Ford,Dijkstra,Spfa,Floyd-Warshall超时)

 

1.Bellman-Ford

Bellman-Ford最重要的一个特点就是可以判负圈,如果图中不存在从s可达的负圈,那么最短路不会经过同一个顶点两次(也就是说最多通过M-1条边),while(true)的循环最多执行M-1次,如果存在从s可达的负圈,那么在第M次循环中也会更新d的值,因此可以检查负圈。

 

01.   

02. #include
03. #include
04. using namespace std;
05.   
06. const int INF=0x7fffffff; 
07. int T,N,M,P,Q;
08. int d[1005],g[105];
09.   
10. struct edge
11. {
12.     int from,to,cost;
13. }es[200010];
14.   
15. int bellman(int s) 
16. {
17.     for(int i=0;i<=M;i++)
18.         d[i]=INF;   
19.     d[s]=0;
20.     while(true)
21.     {
22.         bool update=false;
23.         for(int i=0;i<2*P;i++)
24.         {
25.             edge e=es[i];
26.             if(d[e.from]!=INF && d[e.to]>d[e.from]+e.cost)
27.             {
28.                 d[e.to]=d[e.from]+e.cost;
29.                 update=true;
30.             }
31.         }
32.         if(!update)
33.             break;
34.     }
35.
36.   
37. bool loop()
38. {//判负圈 
39.     for(int i=0;i
40.         for(int j=0;j<2*P;j++)
41.         {
42.             edge e=es[j];
43.             if(d[e.from]!=INF && d[e.to]>d[e.from]+e.cost)
44.             {
45.                 d[e.to]=d[e.from]+e.cost;
46.                 if(i==M-1)
47.                     return true;
48.             }
49.         }
50.     return false;
51.
52.   
53. int main()
54. {
55.     cin>>T;
56.     while(T--)
57.     {
58.         cin>>N>>M>>P>>Q;
59.         for(int i=0;i
60.             cin>>g[i];
61.         for(int i=0;i
62.         {
63.             cin>>es[i].from>>es[i].to>>es[i].cost;
64.             es[i+P].from=es[i].to;//以Q为出发点反向建立邻接表 
65.             es[i+P].to=es[i].from;
66.             es[i+P].cost=es[i].cost;            
67.         }       
68.         bellman(Q);
69.         int res=INF;
70.         for(int i=0;i
71.             if(res>d[g[i]])
72.                 res=d[g[i]];
73.         cout<
74.     }
75.     return 0;
76. }


 

 

2.Dijkstra

Dijkstra算法就是先找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离。

 

01.   

02. #include
03. #include
04. #include
05. using namespace std;
06.   
07. const int INF=1000000; 
08. int T,N,M,P,Q;
09. int d[1005],g[105];
10. int cost[1005][1005];
11. bool used[1005];
12.   
13. void dijkstra(int s) 
14. {
15.     for(int i=0;i<=M;i++)
16.     {
17.         d[i]=INF;
18.         used[i]=false;
19.     }   
20.     d[s]=0;
21.     while(true)
22.     {
23.         int k=-1;
24.         for(int i=1;i<=M;i++)
25.             if(!used[i] && (k==-1 || d[i]
26.                 k=i;
27.         if(k==-1)
28.             break
29.         used[k]=true;
30.         for(int i=1;i<=M;i++)
31.             d[i]=min(d[i],d[k]+cost[k][i]); 
32.     }   
33.
34.   
35. int main()
36. {
37.     cin>>T;
38.     while(T--)
39.     {
40.         cin>>N>>M>>P>>Q;
41.         for(int i=0;i
42.             cin>>g[i];
43.         for(int i=0;i<1005;i++)
44.             for(int j=0;j<1005;j++)
45.                 cost[i][j]=INF;
46.         for(int i=0;i
47.         {
48.             int x,y,z;
49.             cin>>x>>y>>z;
50.             cost[x][y]=z;//邻接矩阵 
51.             cost[y][x]=z;           
52.         }
53.         dijkstra(Q);
54.         int res=INF;
55.         for(int i=0;i
56.             if(res>d[g[i]])
57.                 res=d[g[i]];
58.         cout<
59.     }
60.     return 0;
61. }


使用堆优化后,速度和内存会减少很多

 

01.   

02. #include
03. #include
04. #include
05. #include
06. using namespace std;
07.   
08. const int INF=1000000; 
09. int T,N,M,P,Q;
10. int d[1005],g[105];
11. typedef pair<int,int> pa;
12.   
13. struct edge{
14.     int to,cost;
15. };
16. vector v[1005];
17.   
18. void dijkstra(int s) 
19. {   
20.     priority_queue,greater > que;
21.     memset(d,INF,sizeof(d));
22.     d[s]=0;
23.     que.push(pa(0,s));
24.     while(!que.empty())
25.     {
26.         pa pai=que.top();
27.         que.pop();
28.         int k=pai.second;
29.         if(d[k]
30.             continue;
31.         for(int i=0;i
32.         {
33.             edge e=v[k][i];
34.             if(d[e.to]>d[k]+e.cost)
35.             {
36.                 d[e.to]=d[k]+e.cost;
37.                 que.push(pa(d[e.to],e.to));
38.             }
39.         }
40.     }
41.
42.   
43. int main()
44. {
45.     cin>>T;
46.     while(T--)
47.     {
48.         cin>>N>>M>>P>>Q;
49.         memset(v,0,sizeof(v));
50.         for(int i=0;i
51.             cin>>g[i];
52.         for(int i=0;i
53.         {
54.             edge e;
55.             int x,y,z;
56.             cin>>x>>y>>z;
57.             e.to=y;
58.             e.cost=z;//邻接表
59.             v[x].push_back(e);
60.             e.to=x;
61.             v[y].push_back(e);      
62.         }
63.         dijkstra(Q);
64.         int res=INF;
65.         for(int i=0;i
66.             if(res>d[g[i]])
67.                 res=d[g[i]];
68.         cout<
69.     }
70.     return 0;
71. }


 

 

3.Spfa

Spfa是Bellman-Ford算法的一种队列优化实现,减少了不必要的计算

 

01.    
02. #include
03. #include
04. #include
05. #include
06. using namespace std;
07.   
08. const int INF=1000000; 
09. int T,N,M,P,Q;
10. int d[1005],g[105],cost[1005][1005];
11. bool used[1005];
12.   
13. int spfa(int s)
14. {
15.      memset(d,INF,sizeof(d));
16.      memset(used,0,sizeof(used));
17.      queue<int> que;
18.      d[s]=0;
19.      used[s]=true;
20.      que.push(s);
21.      while(!que.empty())
22.      {
23.          int k=que.front();
24.          que.pop();
25.          for(int i=0;i
26.          {//存在负权时当某点的入队次数超过顶点数返回
27.             if(d[i]>d[k]+cost[k][i])
28.             {
29.                d[i]=d[k]+cost[k][i];
30.                if (!used[i])
31.                {
32.                     que.push(i);
33.                     used[i]=true;    
34.                }        
35.             }            
36.          }
37.         used[k]=false;            
38.     }    
39.
40.   
41. int main()
42. {
43.     cin>>T;
44.     while(T--)
45.     {
46.         cin>>N>>M>>P>>Q;
47.         for(int i=0;i<=M;i++)
48.             for(int j=0;j<=M;j++)
49.                 cost[i][j]=INF;
50.         for(int i=0;i
51.             cin>>g[i];
52.         for(int i=0;i
53.         {
54.             int x,y,z;
55.             cin>>x>>y>>z;
56.             cost[x][y]=z;
57.             cost[y][x]=z;   
58.         }
59.         spfa(Q);
60.         int res=INF;
61.         for(int i=0;i
62.             if(res>d[g[i]])
63.                 res=d[g[i]];
64.         cout<
65.     }
66.     return 0;
67. }


 

4.Floyd-Warshall

Floyd-Warshall使用的是动态规划的思想,不过复杂度比较大,如果对复杂度要求不高的情况下还是很方便的。

代码超时:

 

01.   

02. #include
03. #include
04. #include
05. using namespace std;
06.   
07. const int INF=1000000; 
08. int T,N,M,P,Q;
09. int d[1005][1005],g[105];
10.   
11. void floyd() 
12. {   
13.     for(int k=1;k<=M;k++)
14.         for(int i=1;i<=M;i++)
15.             for(int j=1;j<=M;j++)
16.                 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
17.
18.   
19. int main()
20. {
21.     cin>>T;
22.     while(T--)
23.     {
24.         cin>>N>>M>>P>>Q;
25.         for(int i=0;i<=M;i++)
26.             for(int j=1;j<=M;j++)
27.                 if(i==j)
28.                     d[i][j]=0;
29.                 else
30.                     d[i][j]=INF;
31.         for(int i=0;i
32.             cin>>g[i];
33.         for(int i=0;i
34.         {
35.             int x,y,z;
36.             cin>>x>>y>>z;
37.             d[x][y]=z;
38.             d[y][x]=z;  
39.         }
40.         floyd();
41.         int res=INF;
42.         for(int i=0;i
43.             if(res>d[Q][g[i]])
44.                 res=d[Q][g[i]];
45.         cout<
46.     }
47.     return 0;
48. }


 

你可能感兴趣的:(NYOJ,图论)