题目链接:
点击打开链接
题意描述:给出边建图,然后分别删除各条边,问每一次删边后的所有端点的两两最短路之和,若有一对端点不连通,则返回INF
解题思路:由于每条边的权值为1,所以此处我们可以对dijkstra进行优化,即使用bfs,从源点s出发,对于每一次更新过dis[i]之后直接压入队列即可
dijkstra代码:
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 110
#define MAXE 3010
#define INF 0x7fffffff
using namespace std;
int head[MAXN];
struct Edge{
int to,v,next;
}edge[MAXE*2];
int tol;
void addEdge(int from,int to){
edge[tol].to=to;edge[tol].v=1;edge[tol].next=head[from];head[from]=tol++;
edge[tol].to=from;edge[tol].v=1;edge[tol].next=head[to];head[to]=tol++;
}
struct node{
int x,y;
}e[MAXE];
int tole[MAXN][MAXN];
bool _isexit[MAXN][MAXN][MAXN];
int sum[MAXN];
int n,m;
int dis[MAXN];
bool vis[MAXN];
int pre[MAXN];
typedef struct tmpnode{
int rt,dis;
tmpnode(int _rt,int _dis):rt(_rt),dis(_dis){}
bool operator<(const tmpnode& b)const{
return dis>b.dis;
}
}tmpnode;
int dijkstra(int s,int ee){
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;++i) { dis[i]=INF; pre[i]=-1;}
dis[s]=0;
priority_queue<tmpnode> pq;
while(!pq.empty()) pq.pop();
pq.push(tmpnode(s,0));
while(!pq.empty()){
tmpnode tmp=pq.top(); pq.pop();
int rt=tmp.rt;
if(vis[rt]) continue;
vis[rt]=true;
for(int i=head[rt];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(i!=ee&&(i^1)!=ee&&!vis[to]&&dis[to]>tmp.dis+edge[i].v){
dis[to]=tmp.dis+edge[i].v;
pre[to]=rt;
pq.push(tmpnode(to,dis[to]));
}
}
}
int tsum=0;
for(int i=1;i<=n;++i){
if(dis[i]>=INF) return INF;
tsum+=dis[i];
}
return tsum;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
tol=0; memset(head,-1,sizeof(head));
memset(tole,0,sizeof(tole));
for(int i=1;i<=m;++i){
scanf("%d%d",&e[i].x,&e[i].y);
if(!tole[e[i].x][e[i].y])
addEdge(e[i].x,e[i].y);
else
tol+=2;
tole[e[i].x][e[i].y]++;
tole[e[i].y][e[i].x]++;
}
bool tflag=false;
memset(_isexit,false,sizeof(_isexit));
for(int s=1;s<=n;++s){
sum[s]=dijkstra(s,-1);
if(sum[s]<INF){
for(int i=1;i<=n;++i){
if(pre[i]!=-1){
_isexit[s][pre[i]][i]=true;
_isexit[s][i][pre[i]]=true;
}
}
}
else { tflag=true; break;}
}
for(int k=1;k<=m;++k){
if(tflag) {printf("INF\n");continue;}
int i,ans=0;
for(i=1;i<=n;++i){
if(_isexit[i][e[k].x][e[k].y]&&tole[e[k].x][e[k].y]==1){
int tsum=dijkstra(i,2*k-1);
if(tsum<INF) ans+=tsum;
else break;
}
else ans+=sum[i];
}
if(i>n)
printf("%d\n",ans);
else
printf("INF\n");
}
}
return 0;
}
bfs代码:
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 101
#define MAXE 3001
#define INF 0x7fffffff
using namespace std;
int head[MAXN];
struct Edge{
int to,next;
}edge[MAXE*2];
int tol;
void addEdge(int from,int to){
edge[tol].to=to;edge[tol].next=head[from];head[from]=tol++;
edge[tol].to=from;edge[tol].next=head[to];head[to]=tol++;
}
struct node{
int x,y;
}e[MAXE];
int tole[MAXN][MAXN];///记录每条边出现的次数,用于去除重边
bool _isexit[MAXN][MAXN][MAXN];///记录每个从源点i开始的最短路径经过那些边
int sum[MAXN];///记录从源点i开始的最短路上的点与i的最短距离之和
int n,m;
int dis[MAXN];
bool vis[MAXN];
int pre[MAXN];
typedef struct tmpnode{
int rt,dis;
tmpnode(int _rt,int _dis):rt(_rt),dis(_dis){}
}tmpnode;
int dijkstra(int s,int ee){
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;++i) dis[i]=INF;
dis[s]=0; vis[s]=true;pre[s]=-1;
queue<tmpnode> pq;
while(!pq.empty()) pq.pop();
pq.push(tmpnode(s,0));
while(!pq.empty()){
tmpnode tmp=pq.front(); pq.pop();
int rt=tmp.rt;
for(int i=head[rt];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(i!=ee&&(i^1)!=ee&&!vis[to]&&dis[to]>tmp.dis+1){
dis[to]=tmp.dis+1;
pre[to]=rt;
vis[to]=true;
pq.push(tmpnode(to,dis[to]));///优化之后
}
}
}
int tsum=0;
for(int i=1;i<=n;++i){
if(dis[i]>=INF) return INF;
tsum+=dis[i];
}
return tsum;
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
tol=0; memset(head,-1,sizeof(head));
memset(tole,0,sizeof(tole));
for(int i=1;i<=m;++i){
scanf("%d%d",&e[i].x,&e[i].y);
if(!tole[e[i].x][e[i].y]){///去重边
addEdge(e[i].x,e[i].y);
}
else tol+=2;///便于后面处理
tole[e[i].x][e[i].y]++;
tole[e[i].y][e[i].x]++;
}
bool tflag=false;
memset(_isexit,false,sizeof(_isexit));
for(int s=1;s<=n;++s){
sum[s]=dijkstra(s,-1);
if(sum[s]<INF){
for(int i=1;i<=n;++i){
if(pre[i]!=-1){
_isexit[s][pre[i]][i]=true;///标记边pre[i]->[i]在以s为源点的最短路上出现
_isexit[s][i][pre[i]]=true;
}
}
}
else { tflag=true; break;}
}
for(int k=1;k<=m;++k){
if(tflag) {printf("INF\n");continue;}
int i,ans=0;
for(i=1;i<=n;++i){
if(_isexit[i][e[k].x][e[k].y]&&tole[e[k].x][e[k].y]==1){///对于要删除的边出现在某个最短路径上时重新求最短路径
int tsum=dijkstra(i,2*k-1);
if(tsum<INF) ans+=tsum;
else break;
}
else ans+=sum[i];
}
if(i>n)
printf("%d\n",ans);
else
printf("INF\n");
}
}
return 0;
}