poj2404,很有趣的题目。
1.欧拉回路的充要条件:所有点度为偶数。
2.将两个奇度点补充到偶度的最佳方法是选择任意两个奇度点连最短路径为权的边。
因为如果存在另外的点使得g[a][b]+g[b][c]<g[a][c]则ab最短路就为g[a][b]+g[b][c]。
3.如此,最小的答案就是把求奇度点之间的最小权匹配了。由于这是个一般图网络流或KM好像是搞不定的。 计算了一下状态压缩dp的复杂度(状态)(2^14)*(转移)(14*13/2)=1490944还略大于搜索的复杂度13*11*9*7*5*3=135135,而且搜索还能剪枝神马的,果断就选择简单暴力的搜索了。当然记忆化搜索的方式dp也可以优化一些复杂度。
poj数据一如既往水,0msAC。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define NN 18
#define INF 1000001000
int n,m,g[NN][NN],deg[NN],ans,tans,oddn,us[NN],od[NN];
void floyd(){
int i,j,k;
for(i=1;i<=n;++i){
for(j=1;j<=n;++j)if (i!=j){
for(k=1;k<=n;++k)if (i!=k&&j!=k){
if (g[i][j]>g[i][k]+g[k][j]) g[i][j]=g[i][k]+g[k][j];
}
}
}
}
void getodd(){
oddn=0;
int i;
for(i=1;i<=n;++i){
if (deg[i]%2==1){
od[++oddn]=i;
}
}
}
void dfs(int nn,int now,int cost,int tot){
if (cost>tans) return;
if (now==tot){
if (cost<tans) tans=cost;
return;
}
int i,fi;
for(i=nn;i<=oddn;++i){
if (us[i]==0) {fi=i;break;}
}
us[fi]=1;
for(i=fi+1;i<=oddn;++i)if (us[i]==0){
us[i]=1;
dfs(fi+1,now+1,cost+g[od[fi]][od[i]],tot);
us[i]=0;
}
us[fi]=0;
}
int main(){
int i,j,a,b,c;
while(scanf("%d",&n)&&n){
scanf("%d",&m);
ans=0;
for(i=1;i<=n;++i)
for(j=i+1;j<=n;++j){
g[i][j]=g[j][i]=INF;
}
memset(deg,0,sizeof(deg));
for(i=1;i<=m;++i){
scanf("%d%d%d",&a,&b,&c);
ans+=c;
g[b][a]=g[a][b]=min(g[a][b],c);
deg[a]++;deg[b]++;
}
floyd();
tans=INF;
getodd();
memset(us,0,sizeof(us));
dfs(1,0,0,oddn/2);
ans=tans+ans;
printf("%d\n",ans);
}
return 0;
}
</cstring></cstdio></iostream>