hdu 4284 Travel 2012天津网络赛 状压dp TSP 最短路
2015-09-07 16:32
429 查看
题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4284题目来源:天津网络赛,属于第四五题的样子
简要题意:有NN个城市,MM条有权路,开始一个人有KK块钱,他要逛其中的HH个城市,他的钱可能不够,但在这HH个城市中他可以花DiD_i块买执照并且打工得到CiC_i块,他想要从11号城市除法得到所有的执照并回到11号点,问可不可能。
数据范围:N⩽100;M⩽5000;K⩽105every weighted edge (u,v)1⩽u,v⩽N;w⩽105H⩽15;Ci,Di⩽105N \leqslant 100;\quad M \leqslant 5000; \quad K\leqslant 10^5\\ every\ weighted\ edge\ (u,v)\quad 1\leqslant u, v \leqslant N; \quad w \leqslant 10^5\\ H\leqslant 15;\quad C_i, D_i\leqslant 10^5
题解
读完题目就可以发现这是非常经典的TSP问题,也就是旅行商问题。HH的范围也正好足够。实际上我们只需要考虑那HH就行了,由于需要知道它们之间的最短路,我们可以Floyd先预处理出任意两点间的距离。
TSP问题常用的处理方法是随机算法和状态压缩dp,此处为求出正确的解我们需要使用状压dp。
考虑dp[i][j]dp[i][j]为停留在第ii个点旅行状态为jj的最大剩余钱数,j<1≪Kj<1\ll K,第ii位是否经过了第ii个点(00开始)。
初始化的时方程式如下:
Remain=K−dis[1][Noi]−DiRemain=K-dis[1][No_i]-D_i\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquaddp[i][1≪i]={Remain+Ci Remain⩾0−∞ else\begin{equation}
dp[i][1\ll i]=
\left\{
\begin{aligned}
&Remain+C_i~~~~~~~~~~Remain \geqslant0\\
&-\infty~~~~~~~~~~~~~~~~~~~~~~~~~~~else
\end{aligned}
\right. \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad
\end{equation}状态转移方程式如下:
Remain=dp[from][s xor(1≪to))]−dis[Nofrom][Noto]−DtoRemain=dp[from][s\ xor(1\ll to))]-dis[No_{from}][No_{to}]-D_{to}\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad dp[to][s]={Remain+Cto Remain⩾0∧to is not visited−∞ else\begin{equation}
dp[to][s]=
\left\{
\begin{aligned}
&Remain+C_{to}~~~~~~~~~~~~Remain \geqslant0\wedge to\ is\ not\ visited\\
&-\infty~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~else
\end{aligned}
\right. \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad
\end{equation}转移的条件需要买了执照还剩下钱,这点需要注意。
最终的结果为:
Ans=mini=0H−1(dp[i][(1≪H)−1]−dis[Noi][1])Ans=\min_{i=0}^{H-1}(dp[i][(1\ll H)-1]-dis[No_i][1])\qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad
\qquad \qquad \qquad \qquad判断最终AnsAns是否大于等于00
实现
注意点写即可。比较坑爹的是我一直以为Floyd循环顺序是无关的,结果就跪了很久,其实中间节点要在最外层。。。复杂度Θ(N3+H2H)\Theta(N^3+H2^H)。代码
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <queue> #include <string> #include <vector> #include <set> #include <map> #define pb push_back #define mp make_pair #define all(x) (x).begin(),(x).end() #define sz(x) ((int)(x).size()) #define fi first #define se second using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; LL powmod(LL a,LL b, LL MOD) { LL res=1; a%=MOD; for(; b; b>>=1) { if(b&1)res=res*a%MOD; a=a*a%MOD; } return res; } // head const int INF = 0x3f3f3f3f; const int N = 1<<15; int dp[20] ; int dis[105][105]; struct Node { int no, c, d; }; Node a[20]; int t, n, m, h, u, v, c, k; void floyd(int n) { for (int i = 1; i <= n; i++) { dis[i][i] = 0; } for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { dis[i][j] = min(dis[i][k]+dis[k][j], dis[i][j]); } } } } int dfs(int x, int s) { if (dp[x][s] != -1) return dp[x][s]; int ans = -1; for (int i = 0; i < h; i++) { if (((1<<i)&s) && i != x) { int temp = dfs(i, s^(1<<x)), rem = temp-dis[a[x].no][a[i].no]-a[x].d; if (rem >= 0) { ans = max(ans, rem+a[x].c); } } } return dp[x][s] = ans < 0 ? -2 : ans; } int main() { scanf("%d", &t); while (t--) { memset(dis, INF, sizeof dis); memset(dp, -1, sizeof dp); scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &c); dis[u][v] = dis[v][u] = min(c, dis[u][v]); } floyd(n); scanf("%d", &h); for (int i = 0; i < h; i++) { scanf("%d%d%d", &a[i].no, &a[i].c, &a[i].d); if (k-dis[1][a[i].no]-a[i].d >= 0) { dp[i][1<<i] = k-dis[1][a[i].no]-a[i].d+a[i].c; } } int ans = -1; for (int i = 0; i < h; i++) { ans = max(dfs(i, (1<<h)-1)-dis[1][a[i].no], ans); } puts(ans < 0 ? "NO" : "YES"); } return 0; }
相关文章推荐
- 用HttpUrlConnection抓取网页内容
- TCP-IP协议详解(11) 涅槃 (TCP重新发送)
- java httpURL连接远程服务器并返回数据(httpurlconnection)
- TCP/IP详解之IP协议ARP协议和RARP协议
- TCP-IP协议详解(10) 魔鬼细节 (TCP滑窗管理)
- httpclient远程调用,返回xml
- HttpClient使用详解
- nginx 的简单配置(虚拟主机、来源控制、https)
- 分布式网络爬虫架构-技术选型
- 利用Git和TortoiseGit把代码传输到网络服务器
- Http通用短信接口开发经验及具体开发实现
- HTTP参数CONNETCTION_TIMEOUT和SO_TIMEOUT区别
- 功能测试的测试工作流程
- 通过HttpURLConnection上传
- https协议了解,以及相关协议的解析
- 使用Block,线程封装网络请求
- javaweb学习总结(七)——HttpServletResponse对象(一)
- Linux安装配置apache http://www.cnblogs.com/fly1988happy/archive/2011/12/14/2288064.html
- HttpServletResponse对象
- AFNetworking 网络请求默认基础网址设定