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<iostream>
03. #include<cstring>
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<M;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<N;i++)
60.             cin>>g[i];
61.         for(int i=0;i<P;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<N;i++)
71.             if(res>d[g[i]])
72.                 res=d[g[i]];
73.         cout<<res<<endl;        
74.     }
75.     return 0;
76. }


 

 

2.Dijkstra

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

 

01.   

02. #include<iostream>
03. #include<cstring>
04. #include<algorithm>
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]<d[k]))
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<N;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<P;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<N;i++)
56.             if(res>d[g[i]])
57.                 res=d[g[i]];
58.         cout<<res<<endl;    
59.     }
60.     return 0;
61. }


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

 

01.   

02. #include<iostream>
03. #include<cstring>
04. #include<vector>
05. #include<queue>
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<edge> v[1005];
17.   
18. void dijkstra(int s) 
19. {   
20.     priority_queue<pa,vector<pa>,greater<pa> > 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]<pai.first) 
30.             continue;
31.         for(int i=0;i<v[k].size();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<N;i++)
51.             cin>>g[i];
52.         for(int i=0;i<P;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<N;i++)
66.             if(res>d[g[i]])
67.                 res=d[g[i]];
68.         cout<<res<<endl;    
69.     }
70.     return 0;
71. }


 

 

3.Spfa

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

 

01.    
02. #include<iostream>
03. #include<algorithm>
04. #include<cstring>
05. #include<queue>
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<M;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<N;i++)
51.             cin>>g[i];
52.         for(int i=0;i<P;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<N;i++)         
62.             if(res>d[g[i]])
63.                 res=d[g[i]];
64.         cout<<res<<endl;    
65.     }
66.     return 0;
67. }


 

4.Floyd-Warshall

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

代码超时:

 

01.   

02. #include<iostream>
03. #include<algorithm>
04. #include<cstring>
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<N;i++)
32.             cin>>g[i];
33.         for(int i=0;i<P;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<N;i++)         
43.             if(res>d[Q][g[i]])
44.                 res=d[Q][g[i]];
45.         cout<<res<<endl;    
46.     }
47.     return 0;
48. }


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
孪生素数是指两个素数之间的差值为2的素数对。通过筛选法可以找出给定素数范围内的所有孪生素数的组数。 在引用的代码中,使用了递归筛选法来解决孪生素数问题。该程序首先使用循环将素数的倍数标记为非素数,然后再遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 具体实现过程如下: 1. 定义一个数组a[N,用来标记数字是否为素数,其中N为素数范围的上限。 2. 初始化数组a,将0和1标记为非素数。 3. 输入要查询的孪生素数的个数n。 4. 循环n次,每次读入一个要查询的素数范围num。 5. 使用两层循环,外层循环从2遍历到num/2,内层循环从i的平方开始,将素数的倍数标记为非素数。 6. 再次循环遍历素数数组,找出相邻素数之间差值为2的素数对,并统计总数。 7. 输出总数。 至此,我们可以使用这个筛选法的程序来解决孪生素数问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python用递归筛选法求N以内的孪生质数(孪生素数)](https://blog.csdn.net/weixin_39734646/article/details/110990629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [NYOJ-26 孪生素数问题](https://blog.csdn.net/memoryofyck/article/details/52059096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值