AtCoder Beginner Contest 338F - Negative Traveling Salesman【floyd+状态压缩dp】

本文主要是介绍AtCoder Beginner Contest 338F - Negative Traveling Salesman【floyd+状态压缩dp】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原题链接:https://atcoder.jp/contests/abc338/tasks/abc338_f

Time Limit: 6 sec / Memory Limit: 1024 MB

Score: 500 points、

问题陈述

有一个有N个顶点和M条边的加权简单有向图。顶点的编号为 1 到 N,i/th 边的权重为 Wi​,从顶点 Ui​ 延伸到顶点Vi​。权重可以为负,但该图不包含负循环。

确定是否存在至少访问每个顶点一次的行走。如果存在这样的行走,请找出所遍历的边的最小总权重。如果同一条边被多次遍历,则每次遍历都要加上这条边的权重。

这里的 "至少访问每个顶点一次的行走 "是指满足以下两个条件的顶点序列v1​,v2​,…,vk​:

  • 对于每个 i 有一条边从顶点 vi​ 延伸到顶点 vi+1​。
  • 对于每个 j (1≤j≤N) 都有 i (1≤i≤k) 这样的边 vi​=j 。

限制因素

  • 2≤N≤20
  • 1≤M≤N(N−1)
  • 1≤Ui​,Vi​≤N
  • Ui​\neqVi​
  • (Ui​,Vi​)\neq(Uj​,Vj​)
  • −1e6≤Wi​≤1e6
  • 给定图形不包含负循环。
  • 所有输入值均为整数。

输入输出描述

Sample Input 1Copy

3 4
1 2 5
2 1 -3
2 3 -4
3 1 100

Sample Output 1Copy

-2

按照 2→1→2→3 的顺序跟随顶点,可以访问所有顶点至少一次,所遍历的边的总重量为 (−3)+5+(−4)=−2。这是最小值。

Sample Input 2Copy

3 2
1 2 0
2 1 0

Sample Output 2Copy

No

没有至少访问所有顶点一次的行走。

Sample Input 3Copy

5 9
1 2 -246288
4 5 -222742
3 1 246288
3 4 947824
5 2 -178721
4 3 -947824
5 4 756570
2 5 707902
5 1 36781

Sample Output 3Copy

-449429

解题思路:

首先题目要求我们至少经过每个点一次,也就是说我们只要找到一条路径经过了每个点并且这条路径权值总和最小,也就是说我们并不关心每个点经过了几次,只要经过了就行了,例如如果我们找到了一条权值总和最小并且经过所有点至少一次的路径a->b->c->b->d,我们考虑的路径集合应该是a->b->c->d,,也就是说c->b->d中间的b只是c->d最短路径经过的一个点而已,也就是说我们只需要考虑走过每个点的顺序即可,确定了顺序之后,任意俩个点之间的距离应该使用最短路径,由于不存在负环,任意俩个点之间肯定是存在最短路径的,并且最短路径的长度肯定是确定的,这个题目点的个数最多只有20个,对于考虑哪种走的顺序总路径最短,我们可以考虑状态压缩dp,然后需要提前预处理任意俩个点之间的最短路,可以采用floyd算法才求任意俩点之间的最短路径,预处理之后状态压缩dp处理即可,具体分析见代码处。

状态压缩dp处理过程

状态定义:

定义f[i][j]表示当前走的点的集合为i,并且走过的最后一个点为j的所有方案的最短路径。

初始化:

f[1<<i][i]=0,当前集合只有一个点,就是起点。

状态转移:

当前走过的最后一个点是j,需要考虑倒数第二个点k,用来转移

f[i][j]=min(f[i^(1<<j][k]+d[k][j])

最终答案:

最终走过的点的集合肯定是(1<<n)-1,然后走过的最后一个点可以是任意一个点,所以答案就是min(f[(1<<n)-1][i]) (0<i<n)

时间复杂度:floyd预处理时间复杂度为O(n^3),n=20,这个时间大概是8e3,状态压缩dp处理时间复杂度为O((2^n)*n*n),这个时间大概为4e8,这个时间复杂度很高了,但是这个题目给了6s的时间,所以是可以过的,最终是时间复杂度为O((n^3)+(2^n)*n*n)。

空间复杂度:d数组空间为O(n^2),dp数组f空间为O((2^n)*n),最终空间复杂度为O((n^2)+(2^n)*n),空间大概是(20^2+(2^20)*20),大概是2e7*4/1e6=80M,这个题目给了1024M,空间肯定是足够的。

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 25, M = 1 << 20, INF = 0x3f3f3f3f;int n, m;
int d[N][N], f[M][N];void floyd()
{for (int k = 0; k < n; k++)for (int i = 0; i < n; i++)for (int j = 0; j < n; j++){if (d[i][k] == INF || d[k][j] == INF)continue;d[i][j] = min(d[i][j], d[i][k] + d[k][j]);}
}
int main()
{cin >> n >> m;for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)if (i == j)d[i][j] = 0;elsed[i][j] = INF;for (int i = 0; i < m; i++){int u, v, w;scanf("%d%d%d", &u, &v, &w);u--, v--;d[u][v] = w;    //题目说了不存在重边。所以这里可以直接赋值,如果存在重边应该取所有重边的最小值}//floyd预处理任意俩个点之间的最短路floyd();memset(f, 0x3f, sizeof f);//初始之起点for (int i = 0; i < n; i++)f[1 << i][i] = 0;//状态压缩dp处理过程for (int i = 0; i < 1 << n; i++)  //第一维枚举走过的点的集合for (int j = 0; j < n; j++)   //第二维枚举当前走的点的集合中的最后一个点{if (~i >> j & 1)    //当前最后一个点是j,那么当前走过的点的集合必须包含j,continue;for (int k = 0; k < n; k++){if (j == k)   //不可能自己走到自己continue;if (~i >> k & 1) //前一个点是k,所以当前走过的点的集合i中必须包含kcontinue;if (f[i ^ (1 << j)][k] == INF || d[k][j] == INF)  //INF表示某种状态不存在或者俩个点之间不存在边,不能用于转移continue;f[i][j] = min(f[i][j], f[i ^ (1 << j)][k] + d[k][j]);}}int ans = INF;//当前走过的点的集合肯定是(1<<n)-1,最后一个点可以是任意一个点for (int i = 0; i < n; i++)ans = min(ans, f[(1 << n) - 1][i]);if (ans == INF)   //不存在走过每个点至少一次的路径,输出Noputs("No");else         //存在走过每个点至少一次的路径,输出最短路径的长度cout << ans << endl;return 0;
}

这篇关于AtCoder Beginner Contest 338F - Negative Traveling Salesman【floyd+状态压缩dp】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/663268

相关文章

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Python利用PIL进行图片压缩

《Python利用PIL进行图片压缩》有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所以本文为大家介绍了Python中图片压缩的方法,需要的可以参考下... 有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所有可以对文件中的图

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Qt实现文件的压缩和解压缩操作

《Qt实现文件的压缩和解压缩操作》这篇文章主要为大家详细介绍了如何使用Qt库中的QZipReader和QZipWriter实现文件的压缩和解压缩功能,文中的示例代码简洁易懂,需要的可以参考一下... 目录一、实现方式二、具体步骤1、在.pro文件中添加模块gui-private2、通过QObject方式创建

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上