正题

题目链接:https://www.luogu.com.cn/problem/P6085


题目大意

\(n\)个点的一张无向图,有\(k\)条必走边,\(m\)条其他边,求从\(1\)出发经过必走边后回到起点的最短路径。

\(2\leq n\leq 13,0\leq k\leq 78,2\leq m\leq 200\)


解题思路

可以理解为在只包含必走边的图上加若干条其他边使得这张图存在欧拉回路。

欧拉回路要求所有点联通且度数为偶数,考虑状态压缩\(dp\),设三进制的状态。

\(f_s\),\(0\)表示没有联通,\(1\)表示度数为奇数,\(2\)表示度数为偶数。

然后先考虑加点进来的方式,也就是加进来的点我们只考虑不是必须的边的部分。而且使用这些点类似于一棵树的连接联通的点。(并不是连接成真正的树,而是如果使用了不必须的边的话只和一个点联通)

然后处理完后再考虑调整图的奇偶性,设\(g_S\)表示集合\(S\)中的点为奇数时调整为偶数的最小代价。

然后用\(f\)和\(g\)计算答案就好了。

时间复杂度\(O(3^nn^2)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=14;
struct node{
int to,next;
}a[N*N];
int n,k,m,tot,ans,sta,st,ls[N],p[N],deg[N];
int dis[N][N],g[1<<N],f[1594323];
queue<int> q;
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
int main()
{
memset(dis,0x3f,sizeof(dis));
memset(g,0x3f,sizeof(g));
memset(f,0x3f,sizeof(f));
scanf("%d%d",&n,&k);p[0]=1;dis[0][0]=0;
for(int i=1;i<=n;i++)p[i]=p[i-1]*3,dis[i][i]=0;
for(int i=1;i<=k;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);x--;y--;
addl(x,y);addl(y,x);dis[x][y]=dis[y][x]=min(dis[x][y],w);
deg[x]++;deg[y]++;sta^=(1<<x)^(1<<y);ans+=w;
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);x--;y--;
dis[x][y]=dis[y][x]=min(dis[x][y],w);
}
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]);
int MS=(1<<n);g[0]=0;
for(int s=0;s<MS;s++)
for(int i=0;i<n;i++){
if((s>>i)&1)continue;
for(int j=i+1;j<n;j++)
if(!((s>>j)&1)){
int z=s^(1<<i)^(1<<j);
g[s^z]=min(g[s^z],g[s]+dis[i][j]);
}
}
q.push(2);f[2]=0;
while(!q.empty()){
int s=q.front();q.pop();
for(int x=0;x<n;x++){
if(s/p[x]%3)continue;
int t=s+p[x]*2;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(!(s/p[y]%3))continue;
if(f[t]>=g[MS])q.push(t);
f[t]=min(f[t],f[s]);
}
for(int y=0;y<n;y++){
if(!(s/p[y]%3))continue;
t=s+p[x];
if((t/p[y]%3)==2)t-=p[y];
else t+=p[y];
if(f[t]>=g[MS])q.push(t);
f[t]=min(f[t],f[s]+dis[x][y]);
}
}
}
int mins=g[MS];
for(int s=0;s<p[n];s++){
bool flag=0;int st=0;
for(int i=0;i<n;i++){
if((s/p[i]%3)==0&&deg[i]){flag=1;break;}
if(s/p[i]%3)st|=(1<<i)*(2-s/p[i]%3);
}
if(flag)continue;st^=sta;
mins=min(mins,f[s]+g[st]);
}
printf("%d\n",ans+mins);
return 0;
}

P6085-[JSOI2013]吃货JYY【状压dp,欧拉回路】的更多相关文章

  1. BZOJ 4479: [Jsoi2013]吃货jyy

    一句话题意:求必须包含某K条边的回路(回到1),使得总权值最小 转化为权值最小的联通的偶点 令F[i]表示联通状态为i的最小权值,(3^n状压)表示不在联通块内/奇点/偶点,连边时先不考虑必选的边的度 ...

  2. BZOJ4479 [JSOI2013] 吃货jyy 解题报告(三进制状态压缩+欧拉回路)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4479 Description [故事背景]作为JSOI的著名吃货,JYY的理想之一就是吃 ...

  3. BZOJ4479 : [Jsoi2013]吃货jyy

    若$k\leq 15$,那么可以设$d[i][S]$表示经过了$S$集合的边,现在位于$i$点的最短路. 可以用Dijkstra算法在$O(n^22^k)$时间内求出. 否则若$k>15$,那么 ...

  4. P1433 吃奶酪(洛谷)状压dp解法

    嗯?这题竟然是个绿题. 这个题真的不(很)难,我们只是不会计算2点之间的距离,他还给出了公式,这个就有点…… 我们直接套公式去求出需要的值,然后普通的状压dp就可以了. 是的状压dp. 这个题的数据加 ...

  5. [状压DP]吃奶酪

    吃 奶 酪 吃奶酪 吃奶酪 题目描述 房间里放着 n n n 块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 ( 0 , 0 ) (0,0) (0,0)点处. 输入 第一行有一个整 ...

  6. 洛谷 P1433 吃奶酪 状压DP

    题目描述 分析 比较简单的状压DP 我们设\(f[i][j]\)为当前的状态为\(i\)且当前所在的位置为\(j\)时走过的最小距离 因为老鼠的坐标为\((0,0)\),所以我们要预处理出\(f[1& ...

  7. 【BZOJ-1097】旅游景点atr SPFA + 状压DP

    1097: [POI2007]旅游景点atr Time Limit: 30 Sec  Memory Limit: 357 MBSubmit: 1531  Solved: 352[Submit][Sta ...

  8. 【62测试】【状压dp】【dfs序】【线段树】

    第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...

  9. Codeforces Round #321 (Div. 2) D. Kefa and Dishes 状压dp

    题目链接: 题目 D. Kefa and Dishes time limit per test:2 seconds memory limit per test:256 megabytes 问题描述 W ...

随机推荐

  1. Thread类中yield方法

    Yield方法可以暂停当前正在执行的线程对象,让其他有相同优先级的线程执行.它是一个静态方法而且只保证当前线程放弃CPU占用而不能保证其它线程一定能占用CPU,执行yield()的线程有可能在进入到暂 ...

  2. 【maven】入门教程

    一:Maven简介 1.Maven是什么? 是一个跨平台的项目管理工具.使用java语言开发(Maven 3.3+ require JDK 1.7 or above to execute)2. 为什么 ...

  3. C 静态存储动态存储

    首先,我们可以把程序所占的内存空间分为三个部分:(可以根据静态资源区.栈区.堆区来划分) 静态存储:程序运行期间由系统分配固定得到存储空间(栈): 动态存储:开发者根据自身需要进行动态分配的存储空间( ...

  4. Oracle基本用法(一)

    一.简介 数据库:Oracle数据库的概念和其他数据库不一样,这里的数据库是一个操作系统只有一个库,可以看做Oracle就是一个大的数据库. 实例:一个Oracle实例有一系列的后台进程和内存结构组成 ...

  5. Kafka源码篇 --- 小白也能看懂的Producer的初始化及元数据获取流程

    最近在研究kafka的源码,发现有些小伙伴的源码写的很不错,就想转载一下,让更多的人知道和学习一下. https://blog.csdn.net/weixin_43167418/article/det ...

  6. 备忘录——C#获取微信小程序的云数据库中数据

    目录 0. 背景说明 0.2 获取AccessToken 0.3 数据库查询 0.4 文件下载 2. 简单的封装 3. 简单测试 4. 参考文档 shanzm-2021年8月17日 17:14:24 ...

  7. 眼见为实,看看MySQL中的隐藏列!

    在介绍mysql的多版本并发控制mvcc的过程中,我们提到过mysql中存在一些隐藏列,例如行标识.事务ID.回滚指针等,不知道大家是否和我一样好奇过,要怎样才能实际地看到这些隐藏列的值呢? 本文我们 ...

  8. 使用 antd 的 form 组件来自定义提交的数据格式

    最近使用antd UI 的表单提交数据,数据里面有的是数组,有的是对象.提交的时候还要去校验参数,让人非常头疼.在我仔细看完文档之后,发现 antd 的 form 组件做的非常不错,这些需求通通不是问 ...

  9. ReScript 与 TypeScript,谁是前端圈的“当红辣子鸡”

    摘要: ReScript 和 TypeScript 的出现都是为了更好地使用JavaScript,但两者还是有很大的不同. 本文分享自华为云社区<[云创共驻]ReScript 和 TypeScr ...

  10. python语言介绍及安装

    Python语言简介 Python是什么语言 Python是一种解释型的.可移植的.开源的脚本. 什么是计算机编程 计算机程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合 如何 ...