题目描述
世界上一共有N个JYY愿意去的城市,分别从1编号到N。JYY选出了K个他一定要乘坐的航班。除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班。
一个航班我们用一个三元组(x,y,z)来表示,意义是这趟航班连接城市x和y,并且机票费用是z。每个航班都是往返的,所以JYY花费z的钱,既可以选择从x飞往y,也可以选择从y飞往x。
南京的编号是1,现在JYY打算从南京出发,乘坐所有K个航班,并且最后回到南京,请你帮他求出最小的花费。
Input
输入数据的第一行包含两个整数N和K;
接下来K行,每行三个整数x,y,z描述必须乘坐的航班的信息,数据保证在这K个航班中,不会有两个不同的航班在同一对城市之间执飞;
第K+2行包含一个整数M;
接下来M行,每行三个整数x,y,z 描述可以乘坐也可以不乘坐的航班信息。
Output
输出一行一个整数,表示最少的花费。数据保证一定存在满足JYY要求的旅行方案。
Sample Input
6 3
1 2 1000
2 3 1000
4 5 500
2
1 4 300
3 5 300
Sample Output
3100
Data Constraint
对于10%的数据满足N≤4;
对于30%的数据满足N≤ 7;
对于额外30%的数据满足,JYY可以只通过必须乘坐的K个航班从南京出发到达任意一个城市;
对于100%的数据满足2≤N≤13,0≤K≤78,2 ≤M ≤ 200,1 ≤x,y ≤N,1 ≤z ≤ 10^4。
Hint
样例说明:一个可行的最佳方案为123541。
机票所需的费用为1000+1000+300+500+300=3100。
分析
我们发现这是一个要求从1出发经过必经边回到1的最短路径,容易想到欧拉回路
那么如何处理必经边呢?
容易想到只把必经边加入图,然后度为奇数的点连接它们之间的最短路。
于是容易想到fi,i是一个二进制状态0表示度偶1表示度奇
但是不对劲!再一看题,这可没说是整个图是连通图啊
然后变成三进制状态,0表示图外,1表示图内度奇,0表示图内度偶
然后就很简单了,配对啥的= =
#include <iostream>
#include <cstdio>
#include <queue>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
const int N=14;
const int M=80;
using namespace std;
int n,k,m;
struct Edge {
int u,v,w,nx;
}g[2*M];
int cnt,list[N];
int b[N]={1,3,9,27,81,243,729,2187,6561,19683,59049,177147,531441,1594323},p[N]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};
int f[4782969],bf[16384],d[N][N],iod[N];
void Add(int u,int v,int w) {
g[++cnt].u=u;g[cnt].v=v;g[cnt].w=w;g[cnt].nx=list[u];list[u]=cnt;
}
void Floyd() {
int i,j,k;
rep(i,1,n)
rep(j,1,n)
rep(k,1,n)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
void Prepare() {
int i,j,k;
memset(bf,0x3f,sizeof bf);
bf[0]=0;
rep(i,0,(1<<n)-1)
rep(j,1,n-1)
if (!(i&p[j-1]))
rep(k,j+1,n)
if (!(i&p[k-1]))
bf[i^p[j-1]^p[k-1]]=min(bf[i^p[j-1]^p[k-1]],bf[i]+d[j][k]);
}
void Get_connected() {
queue<int> q;
int a[N];
while (!q.empty()) q.pop();
memset(f,0x3f,sizeof f);
f[2]=0;q.push(2);
while (!q.empty()) {
int s=q.front();q.pop();
int i,j,k=0;
rep(i,1,n)
if (s/b[i-1]%3) a[++k]=i;
rep(i,1,n)
if (!(s/b[i-1]%3)) {
for (j=list[i];j;j=g[j].nx)
if (s/b[g[j].v-1]%3) {
int ns=s+b[i-1]*2;
if (f[s]>=f[ns]) continue;
if (f[ns]==1061109567) q.push(ns);
f[ns]=f[s];
}
rep(j,1,k) {
int ns=s+b[i-1];
ns+=(s/b[a[j]-1]%3==1)?b[a[j]-1]:-b[a[j]-1];
if (f[s]+d[i][a[j]]>=f[ns]) continue;
if (f[ns]==1061109567) q.push(ns);
f[ns]=f[s]+d[i][a[j]];
}
}
}
}
int Get_couple() {
int s,ns,i,ans=2147483647;
rep(s,0,b[n]-1) {
bool a=0;
rep(i,1,n)
if (list[i]&&!(s/b[i-1]%3)) {
a=1;
break;
}
if (a) continue;
int expect=s;
rep(i,1,n)
if (iod[i]&1) expect+=(s/b[i-1]%3==1)?b[i-1]:-b[i-1];
ns=0;
rep(i,1,n)
if (expect/b[i-1]%3==1) ns^=p[i-1];
ans=min(ans,f[s]+bf[ns]);
}
rep(i,1,cnt)
if (i&1) ans+=g[i].w;
return ans;
}
int main() {
int i;
scanf("%d%d",&n,&k);
memset(d,0x3f,sizeof d);
rep(i,1,k) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
iod[u]++;iod[v]++;
Add(u,v,w);Add(v,u,w);
d[u][v]=d[v][u]=w;
}
scanf("%d",&m);
rep(i,1,m) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
d[u][v]=d[v][u]=min(d[u][v],w);
}
Floyd();
Prepare();
Get_connected();
printf("%d",Get_couple());
}