您的位置:首页 > 理论基础 > 计算机网络

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: