HDU 2433 TRAVEL
http://acm.hdu.edu.cn/showproblem.php?pid=2433
题意:给出边建立图 然后依次删除给出的边,求最短路,如无法连通 则返回INF
这里最短路 = 多源最短路和 即求出对于单源最短路 再for一个循环求出多源最短路 相加
用dijkstra 复杂度为V*(E+V),由于这里很特殊 每条路长度都是1 故可以使用bfs 最先搜到的节点一定是最短的
bfs 时间复杂度 E , 但如果每次拆路都对所有节点重新求最短路 复杂度则是 E*V*E 还多个case 可能不过
这里可以使用used[x][u][v] 来记录对于以x为源点的树 是否使用town[u][v] 这条路 若有,则更新sum[x], 若无 continue
即更新所有有用到被拆路的树。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 这道题最主要是分清哪些是暂时的,哪些存储的是一个case 对于每一个case,used、sum、totalA、town都是不能改变的 对于拆的每一条路 可以暂时改变,如town 但最后还是要恢复 因为拆路只是暂时的 而以上的数组是建路了之后就定下来了 对于vis dis这些只是每次bfs使用的,故不需要保存 只要每次清零即可 */ #include <stdio.h> #include <queue> using namespace std; const int MAXE = 3005, MAXV = 105; struct node { int a, b; }cut[MAXE]; int rn, tn, total, totalA; int town[101][101], sum[MAXV]; //int vis[101]; bool used[MAXV][MAXV][MAXV]; queue<int> q; int vis[MAXV], dis[MAXV]; int bfs(int src, bool mark) { int i; while(!q.empty()) q.pop(); memset(vis, 0, sizeof(vis)); memset(dis, 0, sizeof(dis)); q.push(src); vis[src] = 1; while(!q.empty()) { int num = q.front(); q.pop(); for(i=1; i<=tn; i++) { if(!vis[i] && (town[num][i]>0 || town[i][num]>0)) { vis[i] = 1; if(mark == 0) // 控制是否改变used {used[src][i][num] = 1; used[src][num][i] = 1;} dis[i] += dis[num]+1; q.push(i); } } } int tot = 0; for(i=1; i<=tn; i++) { if(!dis[i] && i != src) return -1; tot += dis[i]; } return tot; } int main() { int i, j; int a, b; while(~scanf("%d %d", &tn, &rn)) { totalA = 0; memset(town, 0, sizeof(town)); memset(sum, 0, sizeof(sum)); memset(used, 0, sizeof(used)); for(i=1; i<=rn; i++) { scanf("%d %d", &a, &b); cut[i].a = a, cut[i].b = b; town[a][b] ++; town[b][a] ++; } for(i=1; i<=tn; i++) { sum[i] = bfs(i, 0); if(sum[i] == -1) // 注意本来是否有不可达的点 有则无论有没拆路都是INF 直接返回 { totalA = -1; break; } else totalA += sum[i]; } for(i=1; i<=rn; i++) { total = totalA ; // 使用一个临时代替不能改变的 town[cut[i].a][cut[i].b] --; town[cut[i].b][cut[i].a] --; if(town[cut[i].a][cut[i].b]>0 ) printf("%d\n", total); else if( total == -1 ) printf("INF\n"); else { bool f = 0; for(j=1; j<=tn; j++) if(used[j][cut[i].a][cut[i].b] == 1) { total -= sum[j]; int tmp = bfs(j, 1); // 不能把bfs()直接赋给sum[x] 因为拆路只是暂时的 if(tmp == -1) { f = 1; break;} total += tmp; } if(f) printf("INF\n"); else printf("%d\n", total); } town[cut[i].a][cut[i].b] ++; town[cut[i].b][cut[i].a] ++; } } return 0; }