您的位置:首页 > 其它

[转]HDU 2433 Travel 最短路 预处理优化

2017-04-15 21:38 330 查看
    原文地址:http://http://blog.csdn.net/linraise/article/details/42155947

    题意是说算出一个图所有点到其他点的最短路的和,然后进行删除某条边再进行处理,对SPFA本来也不是很熟,改来改去始终没能A掉,所以转载一篇,参考代码= =

   

思路:

个人认为这道题的描述有问题,但是不在意这些细节了。题目的大致意思是:给定一个图,邻接顶点距离恒为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: