吃货 JYY / Foodie
吃货 JYY / Foodie\operatorname{吃货\ JYY\ /\ Foodie}吃货 JYY / Foodie
题目链接:luogu P6085\operatorname{luogu\ P6085}luogu P6085 / jzoj 3290\operatorname{jzoj\ 3290}jzoj 3290
题目背景
作为 JSOI 的著名吃货, JYY 的理想之一就是吃遍全世界的美食。要走遍全世界当然需要不断的坐飞机了。而不同的航班上所提供的餐食是很不一样的:比如中国的航班会提供中餐,英国的航班有奶茶和蛋糕,澳大利亚的航班有海鲜,新加坡的航班会有冰激凌……
JYY 选出了一些他特别希望品尝餐食的航班,希望制定一个花费最少的旅游计划,能够从南京出发,乘坐所有这些航班并最后回到南京。
题目
世界上一共有 NNN 个 JYY 愿意去的城市,分别从 111 编号到 NNN 。 JYY 选出了 KKK 个他一定要乘坐的航班。除此之外,还有 MMM 个 JYY 没有特别的偏好,可以乘坐也可以不乘坐的航班。
一个航班我们用一个三元组 (x,y,z)(x,y,z)(x,y,z) 来表示,意义是这趟航班连接城市 xxx 和 yyy ,并且机票费用是 zzz 。每个航班都是往返的,所以 JYY 花费 zzz 的钱,既可以选择从 xxx 飞往 yyy ,也可以选择从 yyy 飞往 xxx 。
南京的编号是 111 ,现在 JYY 打算从南京出发,乘坐所有 KKK 个航班,并且最后回到南京,请你帮他求出最小的花费。
输入
输入数据的第一行包含两个整数 NNN 和 KKK 。
接下来 KKK 行,每行三个整数 x,y,zx,y,zx,y,z 描述必须乘坐的航班的信息,数据保证在这 KKK 个航班中,不会有两个不同的航班在同一对城市之间执飞。
第 K+2K+2K+2 行包含一个整数 MMM ,接下来 MMM 行,每行三个整数 x,y,zx,y,zx,y,z 描述可以乘坐也可以不乘坐的航班信息。
输出
输出一行一个整数,表示最少的花费。数据保证一定存在满足 JYY 要求的旅行方案。
样例输入
6 3
1 2 1000
2 3 1000
4 5 500
2
1 4 300
3 5 300
样例输出
3100
样例解释
一个可行的最佳方案为 1→2→3→5→4→11\rightarrow 2\rightarrow 3\rightarrow 5\rightarrow 4\rightarrow 11→2→3→5→4→1 。
机票所需的费用为 1000+1000+300+500+300=31001000+1000+300+500+300=31001000+1000+300+500+300=3100 。
数据范围
对于 100%100\%100% 的数据, 2≤N≤13,0≤K≤78,2≤M≤200,1≤x,y≤N,1≤z≤1042\leq N\leq 13,0\leq K\leq 78,2\leq M\leq 200,1\leq x,y\leq N,1\leq z\leq 10^42≤N≤13,0≤K≤78,2≤M≤200,1≤x,y≤N,1≤z≤104 。
思路
这道题是一道状压 dp 。
我们弄一个联通图,那要弄出欧拉回路,就是要让每个点的度数是偶数。
那我们就设 f[i]f[i]f[i] 为 iii 在三进制下每一个点度数的状态:
- 没有连通(度数为 000 )则状态为 000
- 度数是奇数,状态是 111
- 度数是偶数,状态是 222
那怎么求呢?
我们可以再设一个 g[i]g[i]g[i] 为 iii 在二进制下为一的每一位对应的点的度数为奇数且成为了连通块。
至于转移这个,就每次多放进去连通的两个点。
接着看怎么转移 f[i]f[i]f[i] 这个玩意。
我们就看已经连通的点,然后枚举两个点,保证一个是已经连通的,然后就连通来转移。
至于两点距离,就 Floyed 求。
求答案就枚举 fff 的每个 iii ,然后首先看有没有把所有必连的边连上,有一个没连就不可以。
接着就把度数是单数的连起来(可以用 g[i]g[i]g[i] 解决),找到所需费用最小的那个。
代码
#include<cstdio>
#include<cstring>
#include<iostream>using namespace std;struct node {int x, to, nxt;
}e[201];
int n, k, x, y, z, le[15], KK, more, m, ans = 2147483647;
int num[15], dis[15][15], hav[15], to;
int g[10001], get3[15], f[2000001];
bool yes;void add(int x, int y, int z) {e[++KK] = (node){z, y, le[x]}; le[x] = KK;e[++KK] = (node){z, x, le[y]}; le[y] = KK;
}void Floyed() {for (int k = 0; k < n; k++)for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}void getg() {for (int i = 0; i < (1 << n); i++)for (int j = 0; j < n; j++)if (!(i & (1 << j)))for (int k = j + 1; k < n; k++)if (!(i & (1 << k)))g[i | (1 << j) | (1 << k)] = min(g[i | (1 << j) | (1 << k)], g[i] + dis[j][k]);
}void getf() {for (int i = 2; i < get3[n]; i++)if (f[i] != 1e9) {hav[0] = 0;for (int j = 0; j < n; j++)if (i / get3[j] % 3)hav[++hav[0]] = j;for (int j = 0; j < n; j++)if (i / get3[j] % 3 == 0) {for (int k = le[j]; k; k = e[k].nxt)if (i / get3[e[k].to] % 3) {to = i + get3[j] * 2;f[to] = min(f[to], f[i]);}for (int k = 1; k <= hav[0]; k++) {to = i + get3[j];if (i / get3[hav[k]] % 3 == 1) to += get3[hav[k]];else if (i / get3[hav[k]] % 3 == 2) to -= get3[hav[k]];f[to] = min(f[to], f[i] + dis[j][hav[k]]);}}}
}void getans() {for (int i = 0; i < get3[n]; i++) {yes = 0;for (int j = 0; j < n; j++)if (num[j] && !(i / get3[j] % 3)) {yes = 1;break;}if (!yes) {int now = i;for (int j = 0; j < n; j++)if (num[j] & 1) {if (now / get3[j] % 3 == 1) now += get3[j];else if (now / get3[j] % 3 == 2) now -= get3[j];}to = 0;for (int j = 0; j < n; j++)if (now / get3[j] % 3 == 1)to |= (1 << j);ans = min(ans, f[i] + g[to]);}}
}int main() {scanf("%d %d", &n, &k);//读入for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)if (i != j)dis[i][j] = 1e9;//初始化for (int i = 1; i <= k; i++) {scanf("%d %d %d", &x, &y, &z);//读入x--;y--;more += z;//算出一定只要少多少钱add(x, y, z);num[x]++;num[y]++;dis[x][y] = min(dis[x][y], z);dis[y][x] = min(dis[y][x], z);}scanf("%d", &m);for (int i = 1; i <= m; i++) {scanf("%d %d %d", &x, &y, &z);//读入x--;y--;dis[x][y] = min(dis[x][y], z);dis[y][x] = min(dis[y][x], z);}Floyed();//求出最短路for (int i = 0; i < (1 << n); i++) g[i] = 1e9;g[0] = 0;//初始化getg();//求出gget3[0] = 1;for (int i = 1; i <= n; i++)get3[i] = get3[i - 1] * 3;for (int i = 0; i < get3[n]; i++)f[i] = 1e9;f[2] = 0;//初始化getf();//求出fgetans();//求出额外要多多少钱printf("%d", more + ans);//输出return 0;
}
吃货 JYY / Foodie相关推荐
- 【jzoj 3290】【luogu P6085】Foodie / 吃货 JYY(数位DP)(欧拉回路)
Foodie / 吃货 JYY 题目链接:jzoj 3290 / luogu P6085 题目大意 有 n 个点,有一些路径一定要走,有一些路径可以走可以不走,都有走的费用. 路径双向,然后问你从 1 ...
- 吃货JYY[JSOI2013][状压][欧拉回路]
文章目录 题目 思路 代码 题目 nnn 个点 mmm 条边无向连通图,每条边有权值,指定 KKK 条边必须选,每条边可以经过多次,问从 111 出发遍历完必须边最后回到 111 的最小花费? n≤1 ...
- bzoj4479: [Jsoi2013]吃货jyy 欧拉回路+状态压缩Dp
bzoj4479: [Jsoi2013]吃货jyy Description [故事背景] 作为JSOI的著名吃货,JYY的理想之一就是吃遍全世界的美食.要走遍全 世界当然需要不断的坐飞机了.而不同的航 ...
- BZOJ4479 [JSOI2013] 吃货jyy 解题报告(三进制状态压缩+欧拉回路)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4479 Description [故事背景] 作为JSOI的著名吃货,JYY的理想之一就是 ...
- 【JZOJ B组】【JSOI2013】吃货JYY
Description 世界上一共有N个JYY愿意去的城市,分别从1编号到N.JYY选出了K个他一定要乘坐的航班.除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班. 一个航班我们用一 ...
- bzoj 4479: [Jsoi2013]吃货jyy 欧拉回路+状压dp
题意 世界上一共有N个JYY愿意去的城市,分别从1编号到N.JYY选出了K个他一定要乘坐的航班.除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班. 一个航班我们用一个三元组(x,y, ...
- 【省选专题一】图论 jzoj 3290【JSOI2013】吃货JYY 状压dp+欧拉回路
Description 世界上一共有N个JYY愿意去的城市,分别从1编号到N.JYY选出了K个他一定要乘坐的航班.除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班. 一个航班我们用一 ...
- jzoj3290. 【JSOI2013】吃货JYY
题目描述 Description 世界上一共有N个JYY愿意去的城市,分别从1编号到N.JYY选出了K个他一定要乘坐的航班.除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班. 一个航 ...
- [状压DP][欧拉回路]吃货JYY
题目描述 世界上一共有N个JYY愿意去的城市,分别从1编号到N.JYY选出了K个他一定要乘坐的航班.除此之外,还有M个JYY没有特别的偏好,可以乘坐也可以不乘坐的航班. 一个航班我们用一个三元组(x, ...
最新文章
- 16进制输出C语言字符常量,基础C语言:进制、常量
- JavaScript验证表单大全
- 从开源小白到 Apache Member,我的成长之路
- 软件架构的相关概念小汇
- 对付网络盗贼的三板斧
- ie11上vue中使用elementui的input框无法输入中文
- Price merge是通过org change的callback来trigger的
- oracle仲裁磁盘是一块磁盘吗,基于ASM冗余设计的架构,仲裁磁盘组应该如何去规划?...
- Ansible 管理windwos服务器(一)
- Android 异步任务
- linux aix 环境,Aix5.3安装Bash环境
- 通达信 c语言,通达信if语句用法,通达信公式编写
- linux服务器有电信和网通,Linux 双网关(电信与联通)
- 2018年嵌入式处理器报告:神经网络加速器的崛起
- java getbean不同实现_JavaBean的属性可读写,编写时set方法和get方法必须配对。
- 旋转屏幕时数据的保存与恢复
- DELL 服务器 PCI-E 6IR 通道卡 6I阵列卡8口SAS SATA (整理)
- c# 去掉字符串最后一个逗号
- angular js 循环数据(死数据) 添加数据 隔行换色 单个删除 排序
- bootstrap 元素