您的位置:首页 > 其它

【hdu】2433 Travel【最短路删边】

2016-06-01 22:12 330 查看

题意:


给出一个n节点m条边的图,设这个图所有点之间最短路之和为sum,然后输出删除每一条边之后的sum值,图不联通输出inf

题解:


第一次计算所有图之间最短路之和的时候

在spfa算法里面记录used[i][j][k]代表以i节点为起点进行spfa操作的时候最短路中经过路径j,k

然后在之后进行删边操作的时候 注意重边

每次都把包含有该条边的也即used[i][j][k]=1的i重新进行一次删边后的spfa就能得出答案

#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=3005,M=105;
struct node
{
int a,b;
}edge
;
int n,m,ans,tmp,town[M][M],sum[M],vis[M],dist[M],a,b;
bool used[M][M][M];
int spfa(int src,bool mark)
{
queue<int>q;
memset(vis,0,sizeof(vis));
memset(dist,0,sizeof(dist));
q.push(src);
vis[src]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=1;i<=n;i++){
if(!vis[i]&&(town[u][i]>0||town[i][u]>0)){
vis[i]=1;
if(mark==0){used[src][i][u]=1;used[src][u][i]=1;}//记录以src为起点的时候的最短路有没有用到某条边
dist[i]+=dist[u]+1;
q.push(i);
}
}
}
int tot=0;
for(int i=1;i<=n;i++){
if(!dist[i]&&i!=src)return -1;
tot+=dist[i];
}
return tot;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
ans=0;
memset(town,0,sizeof(town));
memset(sum,0,sizeof(sum));
memset(used,0,sizeof(used));
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
edge[i].a=a;edge[i].b=b;
town[a][b]++;town[b][a]++;
}
for(int i=1;i<=n;i++){
sum[i]=spfa(i,0);
if(sum[i]==-1){ans=-1;break;}
else ans+=sum[i];
}
for(int i=1;i<=m;i++){//删边过程
tmp=ans;
town[edge[i].a][edge[i].b]--;
town[edge[i].b][edge[i].a]--;
if(ans==-1)printf("INF\n");
else if(town[edge[i].a][edge[i].b]) printf("%d\n",ans);
else{//删边之后重新计算一次以该点为起点的最短路径 有用到这条边的顶点都要重新计算一次
bool flag=0;
for(int j=1;j<=n;j++)
if(used[j][edge[i].a][edge[i].b]==1){
tmp-=sum[j];
int now=spfa(j,1);
if(now==-1)
{flag=1;break;}
tmp+=now;
}
if(flag) printf("INF\n");
else printf("%d\n",tmp);
}
town[edge[i].a][edge[i].b]++;
town[edge[i].b][edge[i].a]++;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: