这个题目的意思是: 题目给出一个无向图 , 问你删除其中一条边之后 , 所有点与点之间的最短路和 。
一开始做这个题目的时候 , 用的是floyd算法的暴力解法 , 结果肯定是超时的。
后面学到了最短路树之后才过掉 。
当每个源点去求最短路时 , 就用一个数组来记录所产生的最短路树 ,
然后后面在再这个树中查找, 是否存在删除的边 , 如果不存在 , 那么这个源点就不要求过最短路时间复杂度为O(1)。
这题目对于求最短路也可以用bfs来做, 因为每条边的权值都是一样的。
代码: time : 1089ms
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 105;
const int INF = 10000000 ;
vectorgrap[MAXN]; //
邻接法记录图
int g[MAXN][MAXN] ;
int n , m , bian[3100][2] , d[MAXN][MAXN] , p[MAXN][MAXN] , sum1 = 0 , bz = 0;
void init()
{
for(int i =
1 ; i <= n; i++)
grap[i].clear();
memset(g , 0
, sizeof(g)); //
记录每条边的条数(因为所有边的权都是1 , 所以没必要记录变的权)
memset(p , 0
, sizeof(p)); //
记录每个点为源点求最短路时所形成的最短路树。
sum1 =
0;
bz =
0;
}
int spfa(int s) // 初始化求所有最短路的和
{
int i ,
done[MAXN] , sum = 0;
memset(done
, 0 , sizeof(done));
for(i = 1; i
<= n; i++) d[s][i] = INF ;
d[s][s] =
0;
queueq
;
q.push(s); // 队列记录下点
while(!q.empty())
{
int u =
q.front() ; q.pop() ;
done[u] =
0;
for(i = 0 ;
i < grap[u].size() ; i++)
{
int v =
grap[u][i];
if(d[s][v]
> (d[s][u] + 1))
{
d[s][v] =
d[s][u] + 1;
p[s][v] =
u;
if(!done[v])
{ q.push(v) ; done[v] = 1; }
}
}
}
for(i = 1; i
<= n; i++)
{
sum +=
d[s][i] ;
if(d[s][i]
== INF) // 如果有某个点是孤立点 ,
那么就直接返回
{
bz =
1; // 记录存在点是孤立点
return sum
;
}
}
return
sum;
}
int spfa1(int s) // 当边改变时求的最短路和 ,
用法和上面那个spfa一样
{
int i ,
done[MAXN] , sum = 0 , d1[MAXN] ;
memset(done
, 0 , sizeof(done));
for(i = 1; i
<= n; i++) d1[i] = INF ;
d1[s] =
0;
queueq
;
q.push(s);
while(!q.empty())
{
int u =
q.front() ; q.pop() ;
done[u] =
0;
for(i = 0 ;
i < grap[u].size() ; i++)
{
int v =
grap[u][i];
if(g[u][v]
&& d1[v] > ( d1[u] + 1 ))
{
d1[v] =
d1[u] + 1;
if(!done[v])
{ q.push(v)
; done[v] = 1;}
}
}
}
for(i = 1; i
<= n; i++)
{
sum += d1[i]
;
if(d1[i]
>= INF)
{
bz =
1;
return
sum;
}
}
return
sum;
}
int main()
{
while(scanf("%d %d" , &n , &m) != EOF)
{
init();
int i , j ,
x , y , k;
for(i = 0 ;
i < m ; i++)
{
scanf("%d
%d" , &x , &y);
if(g[x][y]) // 当有重边时 , 就没有必要在邻接表中记录
{
g[x][y] +=
1;
g[y][x] +=
1;
bian[i][0] =
x;
bian[i][1] =
y;
}
else
{
grap[x].push_back(y);
grap[y].push_back(x);
g[x][y] +=
1;
g[y][x] +=
1;
bian[i][0] =
x;
bian[i][1] =
y;
}
}
int
d_sum[MAXN] ;
for(i = 1; i
<= n; i++)
{
d_sum[i] =
spfa(i); // 记录初始化时每个源点所产生的最短路和
sum1 +=
d_sum[i]; // 记录初始时, 所有最短路的和
if(bz) break;
}
//cout<<sum1<<endl;
if(bz) //
如果存在孤立点 , 那么所有边改变都是输出INF
for(i = 0 ;
i < m ; i++) printf("INF\n");
else
{
int max_sum
;
for(i = 0; i
< m ; i++)
{
x =
bian[i][0] ; y = bian[i][1];
if(g[x][y]
> 1) printf("%d\n" , sum1);
// 是否存在重边
else
{
max_sum =
sum1 ;
bz =
0;
g[x][y] =
g[y][x] = 0;
for(j = 1; j
<= n; j++)
{
for(k = 1; k
<= n; k++)
if((p[j][k]
== x && k == y) || (p[j][k] == y && k ==
x)) break; // 改变的边是否在该最短路树中
if(k <=
n)
{
max_sum -=
d_sum[j];
max_sum +=
spfa1(j); // 改变所有最短路的和
if(bz) break;
}
}
if(bz) printf("INF\n");
// 如果改变边之后存在孤立点 ,
就直接输出INF
else
printf("%d\n" , max_sum);
g[x][y] =
g[y][x] = 1; // 恢复改变的边
}
}
}
}
return
0;
}
一开始做这个题目的时候 , 用的是floyd算法的暴力解法 , 结果肯定是超时的。
后面学到了最短路树之后才过掉 。
当每个源点去求最短路时 , 就用一个数组来记录所产生的最短路树 ,
然后后面在再这个树中查找, 是否存在删除的边 , 如果不存在 , 那么这个源点就不要求过最短路时间复杂度为O(1)。
这题目对于求最短路也可以用bfs来做, 因为每条边的权值都是一样的。
代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 105;
const int INF = 10000000 ;
vectorgrap[MAXN];
int g[MAXN][MAXN] ;
int n , m , bian[3100][2] , d[MAXN][MAXN] , p[MAXN][MAXN] , sum1 = 0 , bz = 0;
void init()
{
}
int spfa(int s)
{
}
int spfa1(int s)
{
}
int main()
{
}