您的位置:首页 > 其它

3077 删边旅行

2016-10-26 16:44 337 查看
Task

n个点m条边的无向联通图,求删除每一条边后,任意两点间的距离和。

数据范围:n<=100个节点,m<=2000条边,边权为1.

Solution

60分O( mn ( n+m ) )暴力bfs

由边权为1让人联想到bfs。

按照题意模拟的暴力思路,删除每一条边O( m ),枚举一个源点O( n ),跑bfs O( n+m ),得该状态下,该点对答案的贡献。可以先判断是否是重边或自环,如果是,那么删除了也一定不会影响答案。 (=_=比赛时想到的写法)

100分O( n^2( n+m ) )构最短路图 排除多余的边

在60分的基础上,怎么做才可以减少枚举删除的边呢?——只删最短路图上的边。

假设x为源点,如果图中存在即使删除了也不会影响结果的边,那么这些边有一个共同的性质:一定不在x的最短路图上,因此只要枚举删除最短路图上的边(因为只有这些边会影响点x对答案的贡献),再bfs重新求最短路。

const int N=103,M=2e3+3;
int n,m,ecnt,tot;
int head
,dis
,sum
,ans[M],Q
,eQ
,num;//eQ边集合
bool use
;
struct edge{
int t,id,nxt;
}e[M<<1];
inline void addedge(int f,int t,int id){
e[++ecnt]=(edge){t,id,head[f]};
head[f]=ecnt;
}
inline void input(){
int i,j,k,a,b;
rd(n);rd(m);
rep(i,1,m){
rd(a);rd(b);
addedge(a,b,i);
addedge(b,a,i);
}
}
inline int bfs(int x,int id){//bfs最短路
int i,j,k,t,l,r,sum=0;
memset(dis,-1,sizeof(dis));
dis[x]=l=r=0;
Q[r++]=x;
while(l<r){
x=Q[l++];
sum+=dis[x];
for(i=head[x];i;i=e[i].nxt){
if(e[i].id==id||~dis[e[i].t])continue;
dis[e[i].t]=dis[x]+1;
Q[r++]=e[i].t;
}
}
num=r;
return sum;
}
inline void dfs(int x){//得到最短路图边
use[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(!use[e[i].t]&&dis[e[i].t]==dis[x]+1){
eQ[++tot]=e[i].id;
dfs(e[i].t);
}
}
inline void build(int rt){//以rt为源点的最短路图
int i,j,k;
sum[rt]=bfs(rt,0);
tot=0;
memset(use,0,sizeof(use));
dfs(rt);
rep(i,1,tot){
if(ans[eQ[i]]==-1)continue;
ans[eQ[i]]+=bfs(rt,eQ[i]);
if(num<n){ans[eQ[i]]=-1;continue;}
ans[eQ[i]]-=sum[rt];
}
}
inline void print(){
int i,j,res=0;
rep(i,1,n)res+=sum[i];
rep(i,1,m){
if(ans[i]==-1){puts("-1");continue;}
sc(ans[i]+res);
}
}
int main(){
int i;
input();
rep(i,1,n)build(i);
print();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bfs