Hduoj2433【SPFA】

/*Travel
Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2364    Accepted Submission(s): 776


Problem Description
One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will always take the shortest way. There are M (M <= 3000) two-way roads connecting the towns, and the length of the road is 1.
Let SUM be the total distance of the shortest paths between all pairs of the towns. Please write a program to calculate the new SUM after one of the M roads is destroyed.


Input
The input contains several test cases.
The first line contains two positive integers N, M. The following M lines each contains two integers u, v, meaning there is a two-way road between town u and v. The roads are numbered from 1 to M according to the order of the input.
The input will be terminated by EOF.


 

Output
Output M lines, the i-th line is the new SUM after the i-th road is destroyed. If the towns are not connected after the i-th road is destroyed, please output “INF” in the i-th line. 

 

Sample Input
5 4
5 1
1 3
3 2
5 4
2 2
1 2
1 2
 

Sample Output
INF
INF
INF
INF
2
2
 

Source
2008 Asia Chengdu Regional Contest Online 
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define INF 99999999
int n, m, map[101][101], sum[101];//map邻接表,sum用来保存初始的小镇i为起点的最短路和
int u[3010], v[3010], fa[101], edge[101][3001];//fa保存最短路的每个点的前驱
bool mark[101][101][101];
//mark用来保存每个小镇的最短路需要经过的边
//求s为起点的最短路
int spfa(int s)
{
	int i, j, k, q[3010], front = 0, rear = 0, d[101], vis[101];
	//initial
	memset(vis, 0, sizeof(vis));
	for(i = 1; i <= n; ++i)
	{
		d[i] = INF;
		fa[i] = i;
	}
	d[s] = 0;
	q[rear++] = s;//push
	while(front < rear)
	{
		k = q[front++];
		vis[k] = 0;//pop
		for(i = 1; i <= edge[k][0]; ++i)
		{
			int t = edge[k][i];   //连接点的编号
			if(map[k][t] > 0 && d[t] > d[k] + 1)
			{
				d[t] = d[k]+1;
				fa[t] = k;    
				if(!vis[t])   //未入队
				{
					q[rear++] = t;
					vis[t] = 1;//push
				}
			}
		}
	}
	j = 0;
	for(i = 1; i <= n; ++i)
	j  += d[i];
	return j;   返回以小镇i为起点的路径和
}
//标记最短路径经过的边
void get_mark(int s)
{
	for(int i = 1; i <= n; ++i)
	if(fa[i] != i)
	{
		mark[s][fa[i]][i] = true;
		mark[s][i][fa[i]] = true;
	}
}
int main()
{
	int i, j, k;
	while(scanf("%d%d", &n, &m) != EOF)
	{
		memset(map, 0, sizeof(map));
		memset(mark, 0, sizeof(mark));
		memset(edge, 0, sizeof(edge));
		//count and save edges
		for(i = 0; i < m; ++i)
		{
			scanf("%d%d", &u[i], &v[i]);
			edge[u[i]][0]++;
			edge[v[i]][0]++;
			edge[u[i]][edge[u[i]][0]] = v[i];
			edge[v[i]][edge[v[i]][0]] = u[i];
			map[u[i]][v[i]]++;   //标记重复边
			map[v[i]][u[i]] = map[u[i]][v[i]];
		}
		int ans = 0;
		//保存最初的小镇的路径和
		for(i = 1; i <= n; ++i)
		{
			sum[i] = spfa(i);
			get_mark(i);   
			ans += sum[i];
		}
		
		for(i = 0; i < m; ++i)
		{	
			if(map[u[i]][v[i]] > 1)//如果重复边则删除后SUM不变
			{
				printf("%d\n", ans);
				continue;
			}
			int temp = ans;
			for(j = 1; j <= n; ++j)
			{
				//如果最短路经过此边
				if( mark[j][u[i]][v[i]] )
				{
					map[u[i]][v[i]] = map[v[i]][u[i]] = 0;//destroyed
					temp += spfa(j);
					if(temp >= INF)
					{
						map[u[i]][v[i]] = map[v[i]][u[i]] = 1;
						break;	
					}
					temp -= sum[j];
					map[u[i]][v[i]] = map[v[i]][u[i]] = 1;
				}
			}
			if(temp < INF)
			printf("%d\n", temp);
			else
			printf("INF\n");
		}
	}
	return 0;
}


题意:总共有n个小镇,每个小镇i都要运送一种特产到其他的小镇j,并且运送路线总是最短路,小镇i的路线总和即为其他所有小镇j到i的最短路的总和,题目中的SUM则为所有i的和,现在给出m条小路,求第i条小路被破坏后的SUM。对每一个i输出一个SUM。

思路:这里最原始的方法就是暴力,对每一条小路被破坏后的图进行SPFA,然后计算总和,但是这必定是超时的。

这里的想法是对于这个总和,我们需要对每一个小镇进行SPFA,求出其他小镇到该小镇的最短路,他们的和即为该小镇的运送路线的长度,最后对每一个小镇的运送路线进行求和即为最初的SUM。然而题目要求的是求出每一条i被破坏后的SUM,如果每次重新构图并求最短路和求和是很费时间的。

那么我们可以 这么考虑,我们将每个i的路线总和求出并保留他们最短路径所经过的边,然后对于每一条被破坏的边,我们对每个i小镇进行查询,看其中最短路径是否经过这条边,倘若经过,则当前i小镇的最短路总和需要重新计算,即进行一SPFA。若不包含,则其和为原始数据。对每一个小镇重新遍历后,再计算SUM。

这里有几个难点,一个是里面有重复边,对于重复边我们构图时可以用map记录重复边的条数,同时记录边。 

其次就是保存的小镇的相连点,需要构图和计数和保存编号,最大程度的简化时间复杂度。

还有一个要注意的是由于边是双向的,所以赋值时需要双向赋值,莫忘莫忘。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机网络期末复习题 201708-201801计算机网络复习指导发布-校考学生!!下载截止于12.5日晚上9点 2017-12-04 23:07 计算机网络复习指导-校内考试 §1.名词解释: 1. 计算机网络 2.网络体系结构 3.高速以太网 4.静态路由选择 5. 动态路由选择 6.子网掩码 8.动态主机配置协议 9.套接字 10.客户/服务器模型(C/S模型) 11.域名系统(DNS) 12.光纤分布式数据接口FDDI §2.简答题: 1.试谈你对网络安全的威胁和防病毒技术的认识。(线下教学课件) 2.简述物理层的四个特性。(线下教学课件) 3.计算机网络的组成(P2-P3) 4.计算机网络的功能(P3) 5.计算机网络标准化的相关组织(P4+线下教学课件) 6.计算机网络的性能指标(P8+线下教学课件) 7.简述你所知道的网络传输介质(P33-34) 8.物理层的四个特性(P34) 9.简述四种帧边界的划分方法(即组帧方法)。(P52-54+线下教学课件) 10.简述停止-等待流量控制(协议)。(P59+P62-P64+线下教学课件) 11.简述时分多路复用(P69+线下教学课件) 12.简述频分多路复用(P68+线下教学课件) 13.简述IPv4地址的分类(P122-123) 14.UDP数据报与IP分组的区别(P187) §3.论述题: 1.试说明数据链路层原语和协议的转换。(线下教学课件) 2.描述常规释放的过程,并画出其示意图。(线下教学课件) 3.奈奎斯特定理公式和香农定理公式的主要区别是什么? 4.试比较电路交换、报文交换和分组交换等三种数据传输方式。(P27-29) 5.谈谈你对差错控制方法的理解。(P54-58+线下教学课件) 6.谈谈域名解析过程(P225-226) 7.ARP和DNS是否有些相似?它们有何区别?(P227) 8.FTP的工作原理。(P228)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值