Solution of CF21D Traveling Graph
CyberPrisoner · · 题解
解决本题的一个重要知识:欧拉路径。
在这里简单介绍一下欧拉路径,我们定义一个点连接它的边的数量为它的度,定义度数为奇数的点为奇点,度数为偶数的点为偶点。对于一个无向图
那么对于本题,我们要从
具体要怎样实现呢?我们很容易发现,每连一条边可以让两个点的度数
最后的
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,inf=1e9;
int d[40][40];//d表示两点的距离
int deg[35],f[1<<21];//deg表示点的度数,f为重复经过的边
int n,m,cnt,ans,tot,a[40];//a为奇点的集合
void floyed(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j&&i!=k&&j!=k){
d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
}
}
}
}
}
int cc(int num){
int res=0;
while(num){
num>>=1;
res++;
}
return res;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=inf;
}
}
for(int i=1,x,y,w;i<=m;i++){
cin>>x>>y>>w;
if(x!=y){
d[x][y]=min(d[x][y],w);//重边只考虑最小的
d[y][x]=d[x][y];
}
deg[x]++,deg[y]++;
ans+=w;
}
floyed();//n^3处理每两个点的距离
for(int i=2;i<=n;i++){
if(deg[i]&&d[1][i]==inf){//非连通图且那个点连的有边
cout<<-1;
return 0;
}
}
for(int i=1;i<=n;i++){
if(deg[i]&1)a[++tot]=i;
}
f[0]=0,cnt=(1<<tot)-1;
for(int i=1;i<=cnt;i++){
f[i]=inf;
if(cc(i)&1)continue;//奇点的个数一定为偶数
for(int j=1;j<=tot;j++){
if((i&1<<(j-1))==0)continue;
for(int k=j+1;k<=tot;k++){
if((i&1<<(k-1))==0)continue;
int s=i^(1<<(j-1))^(1<<(k-1));
f[i]=min(f[s]+d[a[j]][a[k]],f[i]);
}
}
}
cout<<ans+f[cnt];//end
return 0;
}