HDU2433-预处理优化

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/leolinsheng/article/details/42155947

Travel

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1782    Accepted Submission(s): 601

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

思路:

个人认为这道题的描述有问题,但是不在意这些细节了。题目的大致意思是:给定一个图,邻接顶点距离恒为1,

对每一个点都算出其它任意的点到它的最小距离总和。再把所有点的总和相加得到的就是结果。顶点数为N,因为

邻接点距离恒为1,可以用BFS生成一棵以当前顶点为根的最小树。所有节点到根的距离总和就是一个顶点的距离。

如果使用蛮力法,生成一棵最小树BFS时间复杂度为O(n),n<100,共有n个结点O(n*n),每删一条边(m)就需要重新生成,

总复杂度为O(n*n*m)。显然是不可接受的。题目的用意也清晰,就是要我们空间换时间,优化之。没有必要每删一条边就

重新生成一棵BFS最小树。如果删的边不是BFS最小树的树边,忽略之。直接记录最小树的距离结果。

优化点一容易得出:每生成一棵BFS树,就把它的距离记录下来。如果删边不在树上,则直接取之。

如果图本身就不是连通图,则可以输出m个INF就完事,优化点二得到。

优化点三也容易想到:如果删除的边是重边,则也是无影响的。

最坏的情况:删的边刚好是树边,则老实地重新BFS生成最小树。(但是需要十分注意不能破坏图结构和污染已记录的BFS树距离)

//2433 bround first search
//题意真是不清楚,早说是所有点距离全加起来啊

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;

typedef struct Edge
{
	int beg,end;
} Edge;

Edge edge[3001];
int Sum[101] = {0};
int Map[101][101];
bool visited[101];
int prec[101][101];		// prefix,prec[i] store the i-th bfs tree
int N,M;

int BFS(int k,bool is_preprocess = true)
{
	int dis[101] = {0};
	memset(visited,false,sizeof(visited));
	queue<int> Q;
	visited[k] = true;
	Q.push(k);
	int cnt = 1;
	int Sum = 0;
	while (!Q.empty())
	{
		int i = Q.front();Q.pop();
		for (int j=1; j <= N; ++j)
		{
			if (!visited[j] && Map[i][j] > 0)
			{
				visited[j] = true;
				if (is_preprocess)
					prec[k][j] = i;	//记录前驱,只记录第一次遍历的BFS树的节点前驱
				dis[j] = dis[i] + 1;
				Sum += dis[j];
				++cnt;
				Q.push(j);
			}
		}
	}
	return (cnt==N) ? Sum : -1;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("1.txt","r",stdin);
#endif

	int x,y, sum ;
	while (cin >> N >> M)
	{
		memset(Sum,0,sizeof(Sum));
		memset(Map,0,sizeof(Map));
		memset(prec,0,sizeof(prec));
		int i=1;
		for ( ;i <= M; ++i)
		{
			//build the graph
			cin >> x >> y;
			Map[x][y]++;
			Map[y][x]++;
			edge[i].beg = x;
			edge[i].end = y;
		}
		sum = 0;
		i=1;
		for (; i <= N; ++i)
		{
			Sum[i] = BFS(i);
			if (Sum[i]==-1)
				break;
			else
				sum += Sum[i];
		}
		if (i <= N)		//原图为非连通图,无论删哪条边,距离恒为INF
		{
			for (int i=0; i < M; ++i)
				puts("INF");
			continue;
		}
		for (int i=1; i <= M; ++i)
		{
			int x = edge[i].beg;
			int y = edge[i].end;
			if (Map[x][y] > 1)			//有重边,删除其中一条对全图无影响
			{
				cout << sum << endl;
			}
			else					//删的是割边(不可能有Map[][]==0,因为前边过滤了非连通图)
			{
				int sum1 = 0,j=1,s1;
				for (; j <= N; ++j)//遍历全部顶点,蛮力法
				{
					if (prec[j][y]==x || prec[j][x]==y)//x-y在第j棵bfs树上,只能蛮力
					{
						Map[x][y] = Map[y][x] = 0;	//删边

						s1 = BFS(j,false);
						if (s1==-1)	//非连通,直接返回INF
						{
							Map[x][y] = Map[y][x] = 1;	//恢复边
							break;
						}
						sum1 += s1;
						Map[x][y] = Map[y][x] = 1;	//恢复边
					}
					else
					{
						sum1 += Sum[j];
					}
				}
				if (j <= N)
				{
					puts("INF");
					//	continue;
				}
				else
				{
					cout << sum1 << endl;
				}
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/leolinsheng/article/details/42155947
今日推荐