我太弱了。
我们可以知道一个结论就是对于一个图的话假如所有点的度数都是偶数,那么只需要走一波欧拉回路。
所以我们就把奇点补成偶点。
将两个奇点补充到偶点的最佳方法是选择任意两个奇点连最短路径为权的边
然后因为N特别小,所以可以直接用状压搞。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=21; int n,m,dis[N][N],deg[N],f[1<<21]; int dfs(int sta) { if(!sta) return 0; if(f[sta]!=-1) return f[sta]; int lst=0; while(!(sta&(1<<lst))) lst++; int ans=1<<30; for(int i=lst+1;i<=n;i++) if((sta&(1<<i))) ans=min(ans,dfs(sta-(1<<i)-(1<<lst))+dis[lst][i]); return f[sta]=ans; } int main() { while(scanf("%d",&n)==1&&n) { scanf("%d",&m); memset(deg,0,sizeof deg); memset(dis,0x3f,sizeof dis); for(int i=1;i<=n;i++) dis[i][i]=0; int sum=0; for(int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z), dis[x][y]=dis[y][x]=min(dis[x][y],z),sum+=z,deg[x]++,deg[y]++; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); int sta=0; for(int i=1;i<=n;i++) if(deg[i]&1) sta|=(1<<i); memset(f,-1,sizeof f); printf("%d ",sum+dfs(sta)); } return 0; }