「牛客」十二桥问题

题目链接

戳我

\(ps:\)如果没报名可能看不了,有权限,不宜公布题面(可以去baidu)

\(Solution\)

怎么全部写的是分层图或者状压啊?没人跟我一样写折半吗?

我们发现\(k\)只有\(12\),很小啊,那应该从\(k\)下手

我们发现有用的点最多\(25\)个,我们将这点\(x\)离散记为\(id[x]\),他到\(y\)最短路径为\(dis[id[x]][y]\)

我们可以搜索这\(k\)条边的顺序+方向.但是这样复杂度很显然不对

观察他是从\(1\)开始在回到\(1\),这相当了两个从\(1\)开始的路径,我们只需要处理一个,再把他们拼起来就好了。

于是我们搜索\(k/2\)的顺序+方向。记录下\(F[S][k](\)状态为\(S\),即选了那些边,以节点\(k\)结尾的最小长度\()\)的答案。这个应该很好弄吧.只要每次加上两点之间的最短路即可,如果不明白可以看代码

于是我们答案就可以算了.

我们枚举一种状态\(X\),然后另一种状态就是枚举状态的补集,令它为\(Y\).

然后在枚举\(i和j\)表示第一种状态以\(i\)结尾,第二种以\(j\)结尾.则答案就是\(F[X][i]+F[Y][j]+dis[id[i]][j];\)

注意\(k\)为单数的情况有点特殊,\(k/2+1\)的答案也要算一算

搞不懂为什么考场上没有想到状压.

可能要卡卡常但是有点懒,懒得卡了。本来考试可以过的,开了\(O2\),但是比赛结束后就没开了????

#pragma GCC optimize("O2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define int long long
#define rg register
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
const int inf=1e17;
int read(){
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return f*x;
}
struct node{
    int to,next,v;
}a[4000100];
struct node1{
    int id,v;
    bool operator < (const node1 &a) const{
        return a.v<v;
    }
}p,now;
priority_queue<node1>q;
int head[100010],cnt,dis[100010],f[100010],n,m,k,x,y,z;
int X[100010],Y[100010],Z[100010],vis[100010],tot,bj[100010];
int Dis[26][100010];
void add(int x,int y,int c){
    a[++cnt].to=y,a[cnt].next=head[x],a[cnt].v=c,head[x]=cnt;
}
int calc(int x){
    int cnt=0;
    while(x)
        cnt+=x&1,x>>=1;
    return cnt;
}
void dij(int s){
    p.id=s,p.v=0,q.push(p);
    memset(dis,127/3,sizeof(dis));
    memset(f,0,sizeof(f));
    dis[s]=0;
    while(!q.empty()){
        now=q.top(),q.pop();
        if(f[now.id]) continue;
        f[now.id]=1;
        for(int i=head[now.id];i;i=a[i].next){
            int v=a[i].to;
            if(dis[v]>dis[now.id]+a[i].v)
                dis[v]=dis[now.id]+a[i].v,p.id=v,p.v=dis[v],q.push(p);
        }
    }
}
int flag[1001],c[1001],d[1001];
int Ans[100001][30];
int Ans2[100001][30];
void dfs(int x,int ans){
    if(x==k/2){
        int ANS=0,last=1;
        for(int i=1;i<=x;i++){
            if(!d[i]) swap(X[c[i]],Y[c[i]]);
            ANS+=Dis[vis[last]][X[c[i]]]+Z[c[i]],last=Y[c[i]];
            if(i==x) Ans[ans][vis[Y[c[i]]]]=min(Ans[ans][vis[Y[c[i]]]],ANS);
            if(!d[i]) swap(X[c[i]],Y[c[i]]);
        }
    }
    if(x==k-k/2){
        int ANS=0,last=1;
        if(k%2==0) {
            if(!d[x]) swap(X[c[x]],Y[c[x]]);
            Ans2[ans][vis[Y[c[x]]]]=Ans[ans][vis[Y[c[x]]]];
            if(!d[x]) swap(X[c[x]],Y[c[x]]);
            return ;
        }
        for(int i=1;i<=x;i++){
            if(!d[i]) swap(X[c[i]],Y[c[i]]);
            ANS+=Dis[vis[last]][X[c[i]]]+Z[c[i]],last=Y[c[i]];
            if(i==x) Ans2[ans][vis[Y[c[i]]]]=min(Ans2[ans][vis[Y[c[i]]]],ANS);
            if(!d[i]) swap(X[c[i]],Y[c[i]]);
        }
        return ;
    }
    for(int i=1;i<=k;i++)
        if(!flag[i])
            for(int j=0;j<=1;j++)
                d[x+1]=j,c[x+1]=i,flag[i]=1,dfs(x+1,ans|(1<<(i-1))),flag[i]=0;
}
int minx=inf,len;
void dfs(int x,int ans,int l){
    if(ans==k/2){
        int now=l^len;
        for(int j=1;j<=tot;j++)
            for(int k=1;k<=tot;k++)
                minx=min(minx,Ans2[now][j]+Ans[l][k]+Dis[k][bj[j]]);
        return ;
    }
    for(int i=x+1;i<=k;i++)
        dfs(i,ans+1,l|(1<<(i-1)));
}
main(){
    n=read(),m=read(),k=read();
    tot=1,bj[tot]=1,vis[1]=1;
    for(int i=1;i<=m;i++){
        x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
        if(i<=k){
            X[i]=x,Y[i]=y,Z[i]=z;
            if(!vis[x]) vis[x]=++tot,bj[tot]=x;
            if(!vis[y]) vis[y]=++tot,bj[tot]=y;
        }
    }
    memset(Ans,127/3,sizeof(Ans));
    memset(Ans2,127/3,sizeof(Ans2));
    for(int s=1;s<=tot;s++){
        dij(bj[s]);
        for(int i=1;i<=n;i++)
            Dis[s][i]=dis[i];
    }
    dfs(0,0);
    len=(1<<k)-1,Ans2[0][1]=0,Ans[0][1]=0;
    dfs(0,0,0);
    cout<<minx;
}
posted @ 2019-11-08 16:57  撤云  阅读(206)  评论(0编辑  收藏  举报
……