「牛客」十二桥问题
题目链接
\(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;
}