HDU 4284 Travel (状态dp)

  今年天津赛区网络赛的一道题,比赛的时候跟强哥讨论了一下,他的思路很明确,然后就让他去写了。。。赛后偶翻了翻这个题。。。额,还不错的状态dp把。。。就是让我给写搓了。。。贡献n次wa。。。

  题目是给一下点之间的花费,构成一个图(图不是很大,最多100*100)。然后指定一些必须访问的点。并且这些点上有一个先花费Di再收入Ci的过程,问能否实现访问所有这些点。。。

因为指定的点数最多为15,加上1号点最多才17,所以直接用状态压缩就可以。先用floyd找出任意两点间的最小花费。然后dp[status][pos]表示当前状态为status并且最后访问的点为pos时,所有的资金数。最后找一个dp[(1<<h)-1][i] - dis[p[i].num][p[start].num] >= 0的点,如果存在则是YES,否则是NO

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   x < y ? x : y
#define Max(x, y)   x < y ? y : x
#define E(x)    (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   i&(-i)

const int eps = 1e-8;
typedef long long LL;
const int inf = ~0u>>2;

using namespace std;

const int N = 110;
const int M = (1<<16) + 10;

int dis[N][N];
int dp[M][20];
int n, m, my, h, st;

struct node {
    int i;
    int c;
    int d;
    node() {}
    node(int x, int y, int z) : i(x), c(y), d(z) {}
    bool operator < (const node cmp) const {
        return i < cmp.i;
    }
}p[20];

void init() {
    int i, j;
    for(i = 1; i<= n; ++i) {
        for(j = 1; j <= n; ++j)
            dis[i][j] = (i == j) ? 0 : inf;
    }
}

void floyd() {
    int i, j, k;
    for(k = 1; k <= n; ++k) {
        for(i = 1; i <= n; ++i) {
            for(j = 1; j <= n; ++j)
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
        }
    }
}

bool solve() {
    int status, i, j;
    CL(dp, -1);
    for(i = 0; i < h; ++i) {    //初始化
        if(my - dis[p[i].i][p[st].i] - p[i].d >= 0)
            dp[1<<i][i] = my - dis[p[i].i][p[st].i] - p[i].d + p[i].c;
    }
    for(status = 0; status < (1<<h); ++status) {
        for(i = 0; i < h; ++i) {
            if(dp[status][i] == -1) continue;
            for(j = 0; j < h; ++j) {
                if(status&(1<<j))   continue;
                if(dp[status][i] - dis[p[i].i][p[j].i] - p[j].d >= 0) {
                    dp[status|(1<<j)][j] = max(dp[status|(1<<j)][j], dp[status][i] - dis[p[i].i][p[j].i] - p[j].d + p[j].c);
                }
            }
        }
    }
    for(i = 0; i < h; ++i) {
        if(dp[(1<<h)-1][i] - dis[p[i].i][p[st].i] >= 0)  break;
    }
    if(i >= h)  return false;
    return true;
}

int main() {
    //freopen("data.in", "r", stdin);

    int T, x, y, z, i;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d", &n, &m, &my);
        init();
        while(m--) {
            scanf("%d%d%d", &x, &y, &z);
            if(z < dis[x][y]) {
                dis[x][y] = dis[y][x] = z;
            }
        }
        floyd();
        scanf("%d", &h);
        st = -1;    //st表示初始点1的下标
        for(i = 0; i < h; ++i) {
            scanf("%d%d%d", &p[i].i, &p[i].c, &p[i].d);
            if(p[i].i == 1) st = i;
        }
        if(st == -1) {
            p[h] = node(1, 0, 0);    //如果没有再加进去。
            st = h++;
        }
        if(solve()) puts("YES");
        else    puts("NO");
    }
    return 0;
}
posted @ 2012-09-11 21:26  AC_Von  阅读(227)  评论(0编辑  收藏  举报