正题

题目链接: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. 转载自-阮一峰-测试框架 Mocha 实例教程

    测试框架 Mocha 实例教程   作者: 阮一峰 日期: 2015年12月 3日 Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏 ...

  2. C# prism 框架 MVVM框架 Prism系列之事件聚合器

    网址:https://www.cnblogs.com/ryzen/p/12610249.html 本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 ...

  3. bootstrap 冻结表格,冻结表头

    需要的文件下载: bootstrap-table:https://github.com/wenzhixin/bootstrap-table bootstrap-table-fiex-column:ht ...

  4. Leaflet 中 删除 一个 标记(Marker)

    参考:https://blog.csdn.net/qq_34922009/article/details/81184004 下面是我在Leaflet官方文档所找到的答案 ,希望可以帮助到大家 比如以下 ...

  5. 迭代器 与 foreach 的区别

    迭代器的常见运用--Eg:有一组数据 需要对每个符合条件的数据 进行记录 static void Main() { int[] s = new int[] { 1, 2, 8 }; foreach ( ...

  6. JSOUP教程目录

    入门: 1.解析和遍历一个HTML文档 输入: 2.解析一个HTML字符串 3.解析一个body片断 4.从一个URL加载一个Document 5.从一个文件加载一个文档 数据抽取: 6.使用DOM方 ...

  7. WPF---依赖属性(一)

    一.概要 C#中属性是抽象模型的核心部分,而依赖属性是专门针对WPF的. 在WPF库实现中,依赖属性使用普通的C#属性进行了包装,使得我们可以通过和以前一样的方式来使用依赖属性. 依赖属性优点如下: ...

  8. Javascript - 异步操作和读取文件

    node.js读取文件 node.js内置了异步读取文件的模块,可以很方便地读取文件的数据.先创建三个txt文档,在根目录下创建一个readFile.js 输入以下代码,然后在vscode的终端中输入 ...

  9. JDBC中的元数据——3.结果集元数据

    package metadata; import java.sql.Connection; import java.sql.ParameterMetaData; import java.sql.Pre ...

  10. ES6两种静态属性的书写方法

    1.这种可以不用实例化对象就能输出. class Car{ constructor(){ } } Car.tool=4 console.log(Car.tool);//4 2.必须实例化后才能输出.但 ...