3077 删边旅行

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[N],dis[N],sum[N],ans[M],Q[N],eQ[N],num;//eQ边集合 
bool use[N];
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值