HDU 4284Travel(状压DP)

HDU 4284    Travel

有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1

由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然后状态转移就好了

上面求最短路直接用的floyd不会错貌似是因为数据里没有Ci<Di的数据,因为如果存在这种情况的话,虽然不考虑点的花费最短路是可以到的但是实际确实到不了的,导致不能走完所有的H个城市:

1
3 3 5
1 2 1
2 3 1
1 3 10
3
1 8 5
2 2 10
3 20 5

比如这样的数据应该输出NO但答案是YES(被这种自己出的数据坑了好久啊有木有!!!)

  1 //#pragma comment(linker,"/STACK:102400000,102400000")
  2 #include <map>
  3 #include <set>
  4 #include <stack>
  5 #include <queue>
  6 #include <cmath>
  7 #include <ctime>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <cctype>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <iostream>
 14 #include <algorithm>
 15 using namespace std;
 16 #define INF 1e8
 17 #define inf (-((LL)1<<40))
 18 #define lson k<<1, L, mid
 19 #define rson k<<1|1, mid+1, R
 20 #define mem0(a) memset(a,0,sizeof(a))
 21 #define mem1(a) memset(a,-1,sizeof(a))
 22 #define mem(a, b) memset(a, b, sizeof(a))
 23 #define FOPENIN(IN) freopen(IN, "r", stdin)
 24 #define FOPENOUT(OUT) freopen(OUT, "w", stdout)
 25 template<class T> T CMP_MIN(T a, T b) { return a < b; }
 26 template<class T> T CMP_MAX(T a, T b) { return a > b; }
 27 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
 28 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
 29 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
 30 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
 31
 32 //typedef __int64 LL;
 33 //typedef long long LL;
 34 const int MAXN = 600;
 35 const int MAXM = 100005;
 36 const double eps = 1e-13;
 37 //const LL MOD = 1000000007;
 38
 39 int T, N, M, H, Money;
 40 int dis[MAXN][MAXN], add[MAXN], cost[MAXN];
 41 int citys[20], dp[1<<18][18];
 42
 43 void init()
 44 {
 45     int u, v, w, c, a;
 46      mem0(add); mem0(cost);mem1(dp);
 47     scanf("%d %d %d", &N, &M, &Money);
 48     for(int i =0 ; i <= N ;i ++ )
 49     {
 50         dis[i][i] = 0;
 51         for(int j = 0; j <= N ; j ++ )
 52             if(i != j) dis[i][j] = INF;
 53     }
 54     for(int i = 0; i < M; i ++ )
 55     {
 56         scanf("%d %d %d", &u, &v, &w);
 57         dis[u][v] = dis[v][u] = MIN(dis[u][v], w);
 58     }
 59     scanf("%d", &H);
 60     for(int i = 1; i <= H; i ++ )
 61     {
 62         scanf("%d %d %d", &u, &a, &c);
 63         citys[i] = u;
 64         add[i] = a;
 65         cost[i] = c;
 66     }
 67 }
 68
 69 void floyd()
 70 {
 71     for(int k=1;k<=N;k++)
 72     for(int i=1;i<=N;i++)
 73     for(int j=1;j<=N;j++)
 74     {
 75         dis[i][j] = MIN(dis[i][j], dis[i][k] + dis[k][j]);
 76     }
 77 }
 78
 79 int main()
 80 {
 81     //FOPENIN("in.txt");
 82     while(~scanf("%d", &T)) while(T--)
 83     {
 84         init();
 85         floyd();
 86         int ans = -INF; H += 1;
 87         citys[0] = 1; cost[0] = add[0] = 0;
 88         dp[1][0] = Money;
 89         for(int now = 1; now < (1<<H); now ++ )
 90         {
 91             for(int u = 0; u < H; u ++ ) if(dp[now][u] != -1)
 92             {
 93                 for(int v = 1; v < H; v ++ ) if( (now & (1<<v)) == 0 )
 94                 {
 95                     int next = now | (1<<v);
 96                     if(dp[now][u] >= dis[citys[u]][citys[v]] + cost[v] )
 97                     {
 98                         dp[next][v] = MAX(dp[now | (1<<v)][v], dp[now][u] - dis[citys[u]][citys[v]] - cost[v] + add[v]);
 99                     }
100                     if(next == (1<<H) - 1)
101                     {
102                         ans = MAX(ans, dp[next][v]);
103                     }
104                 }
105             }
106         }
107        //printf("%d\n", ans);
108         printf("%s\n", ans >= 0 ? "YES" : "NO");
109     }
110     return 0;
111 }

HDU 4284Travel(状压DP)

时间: 2024-11-03 21:52:01

HDU 4284Travel(状压DP)的相关文章

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

hdu 4906 状压dp

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #includ

HDU 4892 状压dp

[BestCoder Round #5]冠军的奖励是小米3手机一部 恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 Defence of the Trees Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 224    Accepted Submiss

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

hdu 1185 状压dp 好题 (当前状态与上两行有关系)

/* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);(第i行的第j个状态有上一行的第k个状态得到) num[i][j]有两个功能,第一:判断第i行第j个状态是否合法 第二:判断第i行第j个状态的数目 */ #include<stdio.h> #include<string.h> #define N 110 int dp[N][N][N];

HDU 5823 (状压dp)

Problem color II 题目大意 定义一个无向图的价值为给每个节点染色使得每条边连接的两个节点颜色不同的最少颜色数. 对于给定的一张由n个点组成的无向图,求该图的2^n-1张非空子图的价值. n <= 18 解题分析 官方题解: 直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集).这样是3^n的. 一个复杂度更优的做法是把所有独立集都预处理出来,然后作n次or卷积.这样是n^2*2^n的. 枚举子集的子集的时间复杂度是3^n 啊 . 即 sigma( C(n,k

hdu 3254 (状压DP) Corn Fields

poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两种选择,状压DP,dp[i][j]表示第 i 行以state[j]这种状态的时候和方法取值. 具体的参考http://www.tuicool.com/articles/JVzMVj 写的很详细. 1 #include<cstdio> 2 #include<cstring> 3 #inc

HDU 6321 (状压dp)

题目大意:: 为给你n个点(n<=10,nn<=10,n) 初始时没有边相连 然后有m个操作(m<=30000m<=30000) 每次可以添加一条边或删除一条边 允许有重边 要求每次操作过后输出选这个图中不相交的k条边有多少种不同的方案 (k=1,2,3--n/2) 题目分析: n最大只有10 , 所以很容易就可以想到状压DP , 但是我在打的时候并没有想出继承状态 , 后来看了题解才略有一丝感悟: 首先一个特别容易看出的状态是每加/减一条边后的状态是由前一个状态转移过来的 : 而

hdu 5471(状压DP or 容斥)

想了最复杂的思路,用了最纠结的方法,花了最长的时间,蒙了一种规律然后莫名其妙的过了. MD 我也太淼了. 后面想了下用状压好像还是挺好写的,而且复杂度也不高.推出的这个容斥的规律也没完全想透我就CAO. Count the Grid Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 400    Accepted Submission(s)