列表

详情


NC20197. [JSOI2013]吃货JYY

描述

【故事背景】 作为JSOI的著名吃货,JYY的理想之一就是吃遍全世界的美食。要走遍全 世界当然需要不断的坐飞机了。而不同的航班上所提供的餐食是很不一样的:比 如中国的航班会提供中餐,英国的航班有奶茶和蛋糕,澳大利亚的航班有海鲜, 新加坡的航班会有冰激凌……JYY选出了一些他特别希望品尝餐食的航班,希望 制定一个花费最少的旅游计划,能够从南京出发,乘坐所有这些航班并最后回到 南京。 
【问题描述】 世界上一共有N个JYY愿意去的城市,分别从1编号到N。JYY选出了K 个他一定要乘坐的航班。除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班。 
一个航班我们用一个三元组(x,y,z)来表示,意义是这趟航班连接城市x和y, 并且机票费用是z。
每个航班都是往返的,所以JYY花费z的钱,既可以选择从 x飞往y,也可以选择从y飞往x。 
南京的编号是1,现在JYY打算从南京出发,乘坐所有K个航班,并且最后回到南京,请你帮他求出最小的花费。

输入描述

输入数据的第一行包含两个整数N和K;
接下来K行,每行三个整数x,y,z描述必须乘坐的航班的信息,数据保证在这K个航班中,不会有两个不同的航班在同一对城市之间执飞;
第K+2行包含一个整数M;
接下来M行,每行三个整数x,y,z描述可以乘坐也可以不乘坐的航班信息。
2 ≤ N ≤ 13,0 ≤ K ≤ 78,2 ≤ M ≤ 200,1 ≤ x,y ≤ N,1 ≤ z ≤ 10^4

输出描述

输出一行一个整数,表示最少的花费。数据保证一定存在满足JYY要求的旅行方案。

示例1

输入:

6 3
1 2 1000
2 3 1000
4 5 500
2
1 4 300
3 5 300

输出:

3100

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 450ms, 内存消耗: 8680K, 提交时间: 2019-04-23 11:04:07

#include <cstdio>
#include <cstdlib>
#include <cstring>
#define rep(i, j, k) for(int i = j; i <= k; ++i)
int ri() {
    char ch = getchar(); int x = 0;
    for(;ch < '0' || ch > '9'; ch = getchar()) ;
    for(;ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) - '0' + ch;
    return x;
}
const int N = 14, M = 110, S = 8192, pS = 1594323, inf = 0x3f3f3f3f;
int h[N][N], a[N], d[N], g[S], f[pS], q[pS], nx[M], to[M], pr[N], p[N], bin[N], n, tp, ans;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u); d[u] ^= 1; d[v] ^= 1;}
int b(int s, int x) {return s / p[x] % 3;}
int c(int s, int x) {return s + (b(s, x) == 1 ? p[x] : -p[x]);}
int Up(int &a, int b) {return a < b ? a : a = b;}
void Pre() {
    bin[0] = 1; p[0] = 1; rep(i, 1, n) bin[i] = bin[i - 1] << 1, p[i] = p[i - 1] * 3;
    rep(k, 1, n) rep(i, 1, n) if(k != i) rep(j, 1, n) if(k != j && j != i)
        Up(h[i][j], h[i][k] + h[k][j]);
    memset(g, 0x3f, sizeof(g)); g[0] = 0; 
    rep(s, 0, bin[n] - 1) rep(i, 1, n) if(~s & bin[i - 1]) rep(j, i + 1, n) if(~s & bin[j - 1])
        Up(g[s ^ bin[i - 1] ^ bin[j - 1]], g[s] + h[i][j]);
}
void Dp() {
    memset(f, 0x3f, sizeof(f)); f[2] = 0; int L = 0, R; q[R = 1] = 2;
    for(int s = q[++L], tp = 0; L <= R; s = q[++L], tp = 0) {
        rep(i, 1, n) if(b(s, i - 1)) a[++tp] = i;
        rep(u, 1, n) if(!b(s, u - 1)) {
            int t = s + p[u - 1] * 2;
            for(int i = pr[u]; i; i = nx[i]) if(b(s, to[i] - 1))
                {if(f[t] == inf) q[++R] = t; Up(f[t], f[s]);}
            rep(i, 1, tp) if(h[a[i]][u] != inf) {
                t = c(s, a[i] - 1) + p[u - 1]; if(f[t] == inf) q[++R] = t;
                Up(f[t], f[s] + h[a[i]][u]);
            }
        }
    }
}
bool check(int s) {rep(i, 1, n) if(pr[i] && !b(s, i - 1)) return false; return true;}
void Calc() {
    ans = inf;
    rep(s, 0, p[n] - 1) if(check(s)) {
        int t = 0;
        rep(i, 1, n) if(d[i] ^ (2 - b(s, i - 1) & 1)) t |= bin[i - 1];
        Up(ans, f[s] + g[t]);
    }
}
int main() {
    n = ri(); memset(h, 0x3f, sizeof(h)); int W = 0;
    for(int k = ri();k--;) {
        int u = ri(), v = ri(), w = ri(); adds(u, v); 
        h[v][u] = Up(h[u][v], w); W += w;
    }
    for(int k = ri();k--;) {
        int u = ri(), v = ri(), w = ri();
        h[v][u] = Up(h[u][v], w);
    }
    Pre(); Dp(); Calc(); printf("%d\n", ans + W);
    return 0;
}

上一题