NYOJ 115 城市平乱 (最短路)
描述
南将军统领着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
分析:
这是一道求解最短路的问题,因为图中的权值没有涉及到负权值的情况,所以用迪杰斯特拉和spfa都能写(如果有负权值的话,迪杰斯特拉就不能用了,只能用spfa)。
说一下迪杰斯特拉和spfa的一些小区别吧,在存储图的时候呢,迪杰斯特拉是用邻接矩阵的方式,而spfa则是用邻接表的方式,这样就能够看出来在访问与某一个点相连的路径的时候(如果数据范围比较大的话),spfa要比迪杰斯特拉快的多,事实上也是如此,还有需要说明的一点就是能用迪杰斯特拉写的题全部都能用spfa写。
然后具体的看一下迪杰斯特拉和spfa算法:
迪杰斯特拉算法:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
int Tu[1002][1002];///存储图的信息
int dis[1002];///到源点的最短距离
int bj[1002];///标记这个点有没有访问过
int jun[1002];///标记军队所在的城市
int N,M,P,Q;
void init()///数据的初始化
{
memset(jun,0,sizeof(jun));
for(int i=1; i<=M; i++)
for(int j=1; j<=M; j++)
{
if(i==j)
Tu[i][j]==0;
else
Tu[i][j]=INF;
}
}
int dij()///迪杰斯特拉算法
{
int sum=0;
for(int i=1; i<=M; i++)
{
dis[i]=Tu[Q][i];///到i点的最短距离
bj[i]=0;///标记这个点有没有访问过
}
bj[Q]=1;///1点访问过了
int flag=Q;///下一个起始点
int cut=1;///城市的个数
while(cut<M)
{
int Min=INF;
for(int i=1; i<=M; i++)
{
if(bj[i]==0&&dis[i]<Min)///找到下一个最短距离
{
Min=dis[i];
flag=i;
}
}
bj[flag]=1;///标记flag点访问过
cut++;///城市个数加
for(int i=1; i<=M; i++)
if(bj[i]==0&&dis[i]>dis[flag]+Tu[flag][i])///这个点没有访问过并且最短距离可以更新
{
dis[i]=dis[flag]+Tu[flag][i];
}
}
int Min=INF;
for(int i=1; i<=M; i++)///求出最小值
{
if(jun[i]==1)
{
if(dis[i]<Min)
Min=dis[i];
}
}
return Min;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&N,&M,&P,&Q);
init();
int a,b,c;
while(N--)
{
scanf("%d",&a);
jun[a]=1;
}
while(P--)
{
scanf("%d%d%d",&a,&b,&c);
Tu[a][b]=Tu[b][a]=min(Tu[a][b],c);///可能会存在重复输入路径的情况
}
printf("%d\n",dij());
}
return 0;
}
在用邻接矩阵存储图的时候,可以动态的申请vector数组来模拟,也可以直接用数组来模拟,两种方法在思路上是完全一样的,不同之处在于时间,vector在插入元素的时候,用push_back(),在数据较多的时候是比较浪费时间的,而用数组模拟的话,有一个头插法的思想,会节省时间。
spfa算法(vector):
#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int N,M,P,Q;
int jun[1002];
int Time[1002][1002];
int dis[1002];
int bj[1002];
vector<int>v[1002];
void init()
{
memset(jun,0,sizeof(jun));
memset(v,0,sizeof(v));
for(int i=0; i<=M; i++)
for(int j=1; j<=M; j++)
{
if(i==j)
Time[i][j]=0;
else
Time[i][j]=INF;
}
}
int spfa()
{
for(int i=1; i<=M; i++)
{
dis[i]=INF;
bj[i]=0;
}
dis[Q]=0;
queue<int>q;
q.push(Q);
bj[Q]=1;
int flag;
while(!q.empty())
{
flag=q.front();
q.pop();
bj[flag]=0;
for(int i=0; i<v[flag].size(); i++)
{
int t=v[flag][i];
if(dis[t]>dis[flag]+Time[flag][t])
{
dis[t]=dis[flag]+Time[flag][t];
if(bj[t]==0)
{
bj[t]=1;
q.push(t);
}
}
}
}
int Min=INF;
for(int i=1; i<=M; i++)
{
// printf("dis %d\n",dis[i]);
if(jun[i]==1)
{
if(dis[i]<Min)
Min=dis[i];
}
}
return Min;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&N,&M,&P,&Q);
init();
int a,b,c;
while(N--)
{
scanf("%d",&a);
jun[a]=1;
}
while(P--)
{
scanf("%d%d%d",&a,&b,&c);
v[a].push_back(b);
v[b].push_back(a);
Time[a][b]=c;
Time[b][a]=c;
}
printf("%d\n",spfa());
}
return 0;
}
spfa算法(数组):
#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int N,M,P,Q,cnt;
int jun[1002];///标记军队所在的城市
int dis[1002];///到源点的距离
int bj[1002];///标记这个点有没有访问过
int head[1002];///头节点
struct Node
{
int to;///相邻的下一个点
int w;///权值
int pre;///前一条边
} node[100002];
void add(int a,int b,int c)
{
node[cnt].to=b;
node[cnt].w=c;
node[cnt].pre=head[a];///采用头插法的思想,给他们的前一条边赋值
head[a]=cnt;
cnt++;
}
void init()///初始化
{
memset(jun,0,sizeof(jun));
memset(head,-1,sizeof(head));
memset(node,0,sizeof(node));
}
int spfa( )
{
for(int i=1; i<=M; i++)
{
dis[i]=INF;
bj[i]=0;
}
dis[Q]=0;
queue<int>q;
q.push(Q);
bj[Q]=1;
int flag;
while(!q.empty())
{
flag=q.front();
q.pop();
bj[flag]=0;
for(int i=head[flag]; i!=-1; i=node[i].pre)///访问所有的与它相连的边
{
int t=node[i].to;
if(dis[t]>dis[flag]+node[i].w)
{
dis[t]=dis[flag]+node[i].w;
if(bj[t]==0)
{
bj[t]=1;
q.push(t);
}
}
}
}
int Min=INF;
for(int i=1; i<=M; i++)
{
// printf("dis %d\n",dis[i]);
if(jun[i]==1)
{
if(dis[i]<Min)
Min=dis[i];
}
}
return Min;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
cnt=0;
scanf("%d%d%d%d",&N,&M,&P,&Q);
init();
int a,b,c;
while(N--)
{
scanf("%d",&a);
jun[a]=1;
}
while(P--)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
printf("%d\n", spfa());
}
return 0;
}
NYOJ 115 城市平乱 (最短路)的更多相关文章
- nyoj 115 城市平乱
城市平乱 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市 ...
- nyoj 115 城市平乱 dijkstra最短路
题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=115 dijkstra算法. #include "stdio.h" ...
- 南洋理工 OJ 115 城市平乱 dijstra算法
城市平乱 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市 ...
- nyist oj 115 城市平乱 (最短路径)
城市平乱 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描写叙述 南将军统领着N个部队.这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安.这M个城市 ...
- Nyoj 城市平乱(图论)
描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市分别编号从1到M. 现在,小工军师告诉南将军,第K号城市发生了暴乱,南将军从各个部队都 ...
- nyoj 115------城市平乱( dijkstra // bellman )
城市平乱 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市 ...
- 城市平乱(Bellman)
城市平乱 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市 ...
- nyoj 115-城市平乱 (BFS)
115-城市平乱 内存限制:64MB 时间限制:1000ms 特判: No 通过数:5 提交数:8 难度:4 题目描述: 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维 ...
- 城市平乱 ---- Dijkstra
题解 : 以暴乱城市 为 源点 向所有点做最短路径 , 然后检查每个不对到暴乱城市的 最短距离 #include<stdio.h> #include<string.h> #in ...
随机推荐
- 获得通讯录并拨打电话 Android
由于通讯录在手机里是以数据库贮存的 所以我们可以通过getContentResolver来获得通讯录 ,这个方法返回一个游标的数据类型,通过moveToNext()方法来获取所有的手机号码信息, 当然 ...
- P2384洛谷 最短路
题目描述 给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径. 输入输出格式 输入格式: 第一行读入两个整数n,m,表示共n个点m条边. 接下来m行,每行三个正整数x,y,z,表示点x到 ...
- tcp四次撒手
转自:http://www.cnblogs.com/cy568searchx/p/3711670.html 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这个原则是当一方完成它的数据发送任 ...
- Java FTP下载文件以及编码问题小结
问题 之前在开发过程中,遇到了一点问题,我要访问一个FTP服务器去下载文件详细情况如下: 1. 需要传入一个可能为中文的文件名: 2. 通过文件名去FTP上寻找该文件: 3. FTP服务器的命名编码为 ...
- Uva 12627 Erratic Expansion(递归)
这道题大体意思是利用一种递归规则生成不同的气球,问在某两行之间有多少个红气球. 我拿到这个题,一开始想的是递归求解,但在如何递归求解的思路上我的方法是错误的.在研读了例题上给出的提示后豁然开朗(顺便吐 ...
- C++常用STL
目录 C++ 常用STL整理 容器和配接器 list(链表) stack(栈) queue(队列) priority_queue(优先队列) set(集合) vector(向量) map&&a ...
- 一个简单的NetCore项目:1 - 搭建框架,生成数据库
1- 启动项目 安装.NETCORE SDK,教程在网上可以搜索的到,这里就不讲述了.简单粗暴的方式就是安装最新的VS2015. 2-搭建框架 2.1 打开VS新建一个项目,在弹出的新建项目对话框中, ...
- PHP变量的实现原理【转】
PHP是一门弱语言,也就说PHP的一个变量可以保存任意类型的变量,PHP是用C语言实现的,而C语言是一个强类型的语言,每个变量都有固定的类型,不能随意改变变量的类型(虽然可以通过强制类型转换,可能会出 ...
- 关于如何利用原生js动态给一个空对象添加属性以及属性值
首先,回忆一下,访问对象属性一共有两种方法:点获取法和方括号获取法.而我们最常用的就是点获取法了.但是当我们遇到需要给对象动态添加属性和属性值时,点获取法好像就不太好用了,尤其是我们不知道属性名的时候 ...
- java中bug调试
根据打印异常位置,定位异常代码,判断有无低级错误,直接更改 否则判断有无相似代码,其他代码和异常代码的区别对比 给内层代码打断点,跟踪异常位置