[牛オフ] 12ブリッジ問題解決レポート

【牛オフ] 12ブリッジ問題

問題の意味

ある\(N- \)点が\(M \)有向グラフの右端と\((\ルN- 50000、\ \ル200000)\ M) \(Kは\)エッジが一定であります通過する\((K \ル12)\)

ノードから\(1 \)の要件を開始:すべての側面を経由しなければならないの後、ノードに戻って\(1 \)は最短経路です。

思考

まず、ポイントの比較的多数が、それのほとんどは無用である、我々は唯一のエンドポイント(またはブリッジ)しなければならないいくつかの側面に焦点を当てる必要があります。

したがって、第1のそれぞれの開始\(1 \)を数回実行するノードおよびエンドポイントのすべてのブリッジの出発点として、\(ダイクストラ\)を、新たなマップを構築する点の数との間の最短距離。

次に、形状圧DP、提供考える\(F [U] [I ] \) 現在の点の\(U \)の辺の集合(ブリッジセット)した後、\(I \)ときに最短経路。

しかし、これは無向グラフであるため、いかなるトポロジー的順序は、直接DPすることはできないがない、
私たちはエッジの集合を列挙するたびに、最初の更新は、すべてのブリッジにエンドポイントを選択し\(F \)値、およびこれらの点は、プライオリティキューに追加した後、サイドダイクストラを実行し、すべてのポイントの残りの部分が更新されました。

コード

#include<bits/stdc++.h>
#define ll long long
#define mkp make_pair
using namespace std;
const int N=5e4+7;
const int M=2e5+7;
const int K=12+7;
const int L=4096+7;
int n,m,k,all,poi,num[N],cnt,bdg[2*K][2*K],bi[K],rec[L];
ll f[2*K+1][L],dis[N],mp[2*K+1][2*K+1],ans,inf;
int lst[N],nxt[2*M],to[2*M],tot;
ll len[2*M];
bool b[N];
struct bridge{
    int x,y;
    ll w;
}e[M];
void add(int x,int y,ll w){
    nxt[++tot]=lst[x];
    to[tot]=y;
    len[tot]=w;
    lst[x]=tot;
}
void read(){
    cin>>n>>m>>k; num[1]=++cnt; int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d%lld",&x,&y,&e[i].w);
        if(!num[x]) num[x]=++cnt;
        if(!num[y]) num[y]=++cnt;
        x=num[x];
        y=num[y];
        e[i].x=x;
        e[i].y=y;
        add(x,y,e[i].w);
        add(y,x,e[i].w);
        if(i<=k){ bdg[x][y]=bdg[y][x]=i; poi=cnt; }
    }
    for(int i=1;i<=k;i++){ bi[i]=1<<i-1; rec[bi[i]]=i; }
    all=(1<<k)-1;
    memset(f,127,sizeof(f));
    memset(mp,-1,sizeof(mp));
    inf=f[0][0];
}
priority_queue<pair<ll,int> >h;
void dijk(int st){
    memset(dis,127,sizeof(dis));
    memset(b,0,sizeof(b));
    dis[st]=0;
    h.push(mkp(0,st));
    while(!h.empty()){
        int u=h.top().second; h.pop();
        if(b[u]) continue;
        b[u]=1;
        for(int i=lst[u];i;i=nxt[i])
            if(dis[to[i]]>dis[u]+len[i]){
                dis[to[i]]=dis[u]+len[i];
                h.push(mkp(-dis[to[i]],to[i]));
            }
    }
    for(int i=1;i<=2*k+1;i++)
        if(dis[i]!=inf) mp[st][i]=dis[i];
}
void print(int x){
    for(int i=1;i<=k;i++){
        printf("%d",x&1);
        x>>=1;
    }
}
void run(int i){
    while(!h.empty()){
        int u=h.top().second; h.pop();
        if(b[u]) continue;
        b[u]=1;
        for(int v=1;v<=n;v++)
            if(mp[u][v]!=-1&&f[v][i]>f[u][i]+mp[u][v]){
                f[v][i]=f[u][i]+mp[u][v];
                h.push(mkp(-f[v][i],v));
            }
    }
}
int main(){
//  freopen("bridge.in","r",stdin);
//  freopen("bridge.out","w",stdout);
    read();
    for(int i=1;i<=2*k+1;i++) dijk(i);
    f[1][0]=0; h.push(mkp(0,1));
    n=poi;
    ans=inf;
    for(int i=0;i<=all;i++){
        for(int j=i;j;j-=j&-j){
            int t=rec[j&-j];
            int x=e[t].x,y=e[t].y;
            f[x][i]=min(f[x][i],f[y][i^bi[t]]+e[t].w);
            f[y][i]=min(f[y][i],f[x][i^bi[t]]+e[t].w);
            h.push(mkp(-f[x][i],x));
            h.push(mkp(-f[y][i],y));
        }
        memset(b,0,sizeof(b));
        run(i);
    }
    for(int i=1;i<=n;i++)
        if(f[i][all]!=inf) ans=min(ans,f[i][all]+mp[i][1]);
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/brucew-07/p/11837513.html