题意:给一个n个点m条边的无向图 分别删除每条边 问删除后的新图中 分别以每个点为原点 到其它点的最短距离之和 图不连通时输出INF
思路:如果对于每一条边删除后都做n次最短路 则时间复杂度为O(m*n*m*log(n)) 时间复杂度太高 仔细分析一下不难发现 只有删除的边是最短路树上的边 各点之间的最短距离才会改变 因此 只要枚举最短路树上的边 时间复杂度就会降到O(n*n*m*log(n)) 可以接受
我的代码效率还是不行... 1903MS险过 - -!
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define REP(i, a, b) for( int i = a; i < b; i++ )
#define FOR(i, a, b) for( int i = a; i <= b; i++ )
#define CLR(a, x) memset( a, x, sizeof a )
#define BUG puts( "****BUG****" )
const int maxn = 100 + 10;
const int maxe = 3000 + 10;
const int INF = 1e5;
struct Edge{
int u, v;
Edge(int u = 0, int v = 0) : u(u), v(v) {}
};
struct SOLVE{
int d[maxn], Q[maxn], mark[maxn][maxn][maxn];
//mark[i][u][v] = 1 代表以点i为原点的单源最短路中 u->v 构成最短路树的一条边
int cnt_edge[maxn][maxn], map[maxn][maxn];
int sum, x[maxn];
int head, tail, cntE, n, m;
Edge edge[maxe];
void init(int n, int m){
this -> n = n;
this -> m = m;
cntE = sum = 0;
CLR(mark, 0);
CLR(cnt_edge, 0);
CLR(map, 0);
CLR(x, 0);
}
void add(int u, int v){
edge[cntE++] = Edge(u, v);
map[u][v] = map[v][u] = 1;
cnt_edge[u][v]++; //处理重边的情况
cnt_edge[v][u]++;
}
int bfs(int s, bool flag){
REP(i, 0, n) d[i] = INF;
d[s] = 0;
head = tail = 0;
Q[tail++] = s;
while(head != tail){
int u = Q[head++];
REP(v, 0, n) if(map[u][v]){
if(d[v] > d[u] + 1){
d[v] = d[u] + 1;
if(flag) mark[s][u][v] = mark[s][v][u] = 1;
//只有在做n次单源最短路时才保存各最短路树的边
Q[tail++] = v;
}
}
}
int sum = 0;
REP(i, 0, n) sum += d[i];
return sum;
}
void solve(){
REP(i, 0, n){
x[i] = bfs(i, true);
sum += x[i];
}
REP(i, 0, m){
int u = edge[i].u, v = edge[i].v, cur_sum = sum;
REP(j, 0, n) if(mark[j][u][v] && cnt_edge[u][v] == 1){
//cnt_edge[u][v] == 1 说明没有重边 这样删边才有意义
map[u][v] = map[v][u] = 0;
cur_sum -= x[j];
int tmp_sum = bfs(j, false);
cur_sum += tmp_sum;
if(tmp_sum >= INF) break;
map[u][v] = map[v][u] = 1;//不要忘了变回去
}
if(cur_sum >= INF) printf("INF\n");
else printf("%d\n", cur_sum);
}
}
}solver;
int n, m;
void solve(){
int u, v;
solver.init(n, m);
REP(i, 0, m){
scanf("%d%d", &u, &v);
solver.add(--u, --v);
}
solver.solve();
}
int main()
{
// freopen("in.txt", "r", stdin);
while(~scanf("%d%d", &n, &m)) solve();
return 0;
}