ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

正边权无向图,一条边两个方向权值不一定相同,求经过点1的最小简单环

简单环包含了点1的一条出边和一条入边,且这两条边不同,因此可以枚举这两条边的编号的二进制表示中哪一位不同,用最短路求此时的最优解,时间复杂度$O(mlog^2m)$

#include<bits/stdc++.h>
using std::swap;
using std::vector;
using std::priority_queue;
const int N=40007,inf=1000000000;
int _(){
    int x=0,c=getchar();
    while(c<48)c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x;
}
int n,m;
struct edge{
    int to,v;
    bool operator<(edge e)const{return v>e.v;}
};
int l[N],ans=inf;
priority_queue<edge>q;
vector<edge>es[N],eS,eT;
bool ed[100007];
void mins(int&a,int b){if(a>b)a=b;}
void cal(){
    q=priority_queue<edge>();
    for(int i=1;i<=n;++i)l[i]=inf;
    for(int i=0;i<eS.size();++i)if(ed[i]){
        edge w=eS[i];
        if(l[w.to]>w.v)q.push((edge){w.to,l[w.to]=w.v});
    }
    while(q.size()){
        edge w=q.top();q.pop();
        if(w.v>=ans)break;
        if(w.v!=l[w.to])continue;
        for(int i=0;i<es[w.to].size();++i){
            edge u=es[w.to][i];
            if(l[u.to]>w.v+u.v)q.push((edge){u.to,l[u.to]=w.v+u.v});
        }
    }
    for(int i=0;i<eT.size();++i)if(!ed[i]){
        edge w=eT[i];
        mins(ans,l[w.to]+w.v);
    }
}
int main(){
    n=_(),m=_();
    for(int i=0,a,b,v1,v2;i<m;++i){
        a=_(),b=_(),v1=_(),v2=_();
        if(a==b)continue;
        if(a==1||b==1){
            if(b==1)swap(a,b),swap(v1,v2);
            eS.push_back((edge){b,v1});
            eT.push_back((edge){b,v2});
        }else{
            es[a].push_back((edge){b,v1});
            es[b].push_back((edge){a,v2});
        }
    }
    for(int t=1;t<eS.size();t<<=1){
        for(int i=0;i<eS.size();++i)ed[i]=i&t;
        cal();
        for(int i=0;i<eS.size();++i)ed[i]^=1;
        cal();
    }
    printf("%d\n",ans);
    return 0;
}

 

posted on 2017-08-09 07:53  nul  阅读(459)  评论(0编辑  收藏  举报