分析:
把问题转化一下,所谓的回路只需要满足:每个点得度数均为偶数即可。
然后可以先把必走的边忽略,让这些边联通且满足上述条件。
做
3
n
3^n
3n的DP,表示每一个点:不连通/度数为奇/度数为偶。(这里要特别注意必走边,尽管我们忽略了它们,但是它们是实际存在的,要参与连通性计算,只不过代价为0,因为它们的代价我们会最后加上)
然后再搞一个 2 n 2^n 2n的DP,表示链接某些点的最小代价。
然后对每个 3 n 3^n 3n的状态,找到哪些点应该补度数。求出一个对应的 2 n 2^n 2n的状态。两个状态之和加上最开始忽略的必走边就是答案。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define SF scanf
#define PF printf
#define MAXS 1594423
#define MAXN 14
#define INF 0x3f3f3f3f
#define MAXB 8292
using namespace std;
int n,m,w1;
int W;
struct node{
int x;
node *nxt;
}edge[MAXN*10];
node *head[MAXN],*ncnt=edge;
int b[MAXN],p[MAXN];
int dp[MAXS],f[MAXB];
void add_edge(int x,int y){
ncnt++;
ncnt->x=y;
ncnt->nxt=head[x];
head[x]=ncnt;
}
int c(int s,int pos){
return (s/p[pos])%3;
}
int tr(int s,int pos){
if(c(s,pos)==1)
return s+p[pos];
else
return s-p[pos];
}
int dist[MAXN][MAXN];
void prepare(){
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
b[0]=1;
p[0]=1;
for(int i=1;i<=n;i++){
b[i]=b[i-1]*2;
p[i]=p[i-1]*3;
}
memset(f,0x3f,sizeof f);
f[0]=0;
for(int mask=0;mask<b[n];mask++){
if(mask==INF)
continue;
for(int i=0;i<n;i++){
if(mask&b[i])
continue;
for(int j=0;j<n;j++){
if((mask&b[j])||j==i)
continue;
f[mask|b[i]|b[j]]=min(f[mask|b[i]|b[j]],f[mask]+dist[i][j]);
}
}
}
}
void Update(int &x,int y){
x=min(x,y);
}
int used[MAXN];
queue<int> q;
void solve(){
memset(dp,INF,sizeof dp);
dp[2]=0;
q.push(2);
while(!q.empty()){
int mask=q.front();
q.pop();
int tmp=0;
for(int i=0;i<n;i++)
if(c(mask,i)!=0)
used[tmp++]=i;
for(int i=0;i<n;i++)
if(c(mask,i)==0){
int mask1=mask+2*p[i];
for(node *v=head[i];v!=NULL;v=v->nxt)
if(c(mask1,v->x)!=0){
if(dp[mask1]==INF)
q.push(mask1);
Update(dp[mask1],dp[mask]);
}
for(int j=0;j<tmp;j++){
if(dist[i][used[j]]==INF)
continue;
mask1=tr(mask,used[j])+p[i];
if(dp[mask1]==INF)
q.push(mask1);
Update(dp[mask1],dp[mask]+dist[i][used[j]]);
}
}
}
}
bool check(int mask){
for(int i=0;i<n;i++)
if(head[i]!=NULL&&c(mask,i)==0)
return 0;
return 1;
}
int d[MAXN];
int get_ans(){
int res=INF;
for(int mask=2;mask<p[n];mask++){
if(check(mask)==0)
continue;
int t=0;
for(int i=0;i<n;i++){
if((d[i]^((mask/p[i])%3==1))==1){
t|=b[i];
}
}
//PF("{%d %d %d %d %d %d %d}\n",mask,t,((mask/p[0])%3==1)^d[0],d[1],d[2],d[3],d[4]);
Update(res,dp[mask]+f[t]);
}
return res;
}
int main(){
SF("%d%d",&n,&m);
memset(dist,INF,sizeof dist);
int u,v;
for(int i=1;i<=m;i++){
SF("%d%d%d",&u,&v,&w1);
u--;
v--;
W+=w1;
Update(dist[u][v],w1);
dist[v][u]=dist[u][v];
add_edge(u,v);
add_edge(v,u);
d[u]^=1;
d[v]^=1;
}
SF("%d",&m);
for(int i=1;i<=m;i++){
SF("%d%d%d",&u,&v,&w1);
u--;
v--;
Update(dist[u][v],w1);
dist[v][u]=dist[u][v];
}
for(int i=0;i<n;i++)
dist[i][i]=0;
prepare();
solve();
PF("%d",get_ans()+W);
}