码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4571 Travel in time (SPFA 或 dp)

时间:2014-05-08 17:12:27      阅读:408      评论:0      收藏:0      [点我收藏+]

标签:dp   spfa   

HDU 4571

大概题意:n个点(<=100)m条边(<=1000)的无向图,每个点有消耗costp和价值moneyp,每条边有消耗coste。问从点s出发到点e,消耗不超过t(<=300)所获得的最大价值。经过边必有消耗coste;经过点时,当取得价值moneyp时消耗costp,即为visit该点;当取得价值0,时消耗也为0,即为pass该点。visit的点的moneyp值必须是严格升序。


解法:

容易看出应该用spfa和dp来解。关键时对visit和pass点的处理。

通过floyd预处理出visit每个点对之间的最小边消耗。然后,加一个超级源点和一个超级终点。超级源点负责pas点s能够到达的点,超级终点负责那些能越过e的点

由于visit的点的moneyp值必须严格升序所以也可以拓扑之后dp

不能用dij,因为本题时求最长路,且有正边。需用spfs


注意:

(1)spfa中跑的状态都是合理的,所以可以初始化dp为0;而dp中枚举的状态不一定是合理的,所以要初始化dp为-1

(2)spfa的两种写法,

先建图在跑spfa。

在跑spfa的过程中判断边。


坑点:本题卡vector,要用手写的链表或邻接矩阵


spfa:

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 111 * 310;

int cost[111], money[111];
int d[111][111];
int dp[111][310];
int inq[111][310];

void floyed(int n)
{
    REP(k, n) REP(i, n) REP(j, n)
    {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    }
}
int n, m, t, s, e;
int spfa(int ss, int ee)
{
    queue<int>qu;
    queue<int>qct;
    memset(dp, 0, sizeof(dp));
    memset(inq, 0, sizeof(inq));

    qu.push(ss);
    qct.push(0);
    inq[ss][0] = 1;

    int ans = 0;
    while (!qu.empty())
    {
        int u = qu.front(); qu.pop();
        int uct = qct.front(); qct.pop();
        inq[u][uct] = 0;
        if (u == ee) ans = max(ans, dp[u][uct]);
        for (int v = 0; v < n; v++)
        {
            if (v == u || (money[u] >= money[v] && v != ee)) continue;

            int vct = uct + d[u][v] + cost[v];
            if (vct <= t && dp[v][vct] < dp[u][uct] + money[v])
            {
                dp[v][vct] = dp[u][uct] + money[v];
                if (!inq[v][vct])
                {
                    qu.push(v);
                    qct.push(vct);
                    inq[v][vct] = 1;
                }
            }
        }
    }
    return ans;
}

int main ()
{
    int test;
    RI(test);
    int ncase = 1;
    while (test--)
    {
        scanf("%d%d%d%d%d", &n, &m, &t, &s, &e);
        memset(d, 0x3f, sizeof(d));
        for (int i = 0; i < n; i++)
            RI(cost[i]);
        for (int i = 0; i < n; i++)
            RI(money[i]);
        for (int i = 0; i < n + 2; i++)
            d[i][i] = 0;
        for (int i = 0; i < m; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            d[x][y] = min(d[x][y], z);
            d[y][x] = d[x][y];
        }
        floyed(n);

        int ss = n;
        int ee = n + 1;
        cost[ss] = money[ss] = 0;
        cost[ee] = money[ee] = 0;
        for (int i = 0; i < n; i++)
            if (d[s][i] != INF) d[ss][i] = d[s][i];
        for (int i = 0; i < n; i++)
            if (d[i][e] != INF) d[i][ee] = d[i][e];
        d[ss][ee] = d[s][e];
        n += 2;

        int ans = spfa(ss, ee);
        printf("Case #%d:\n", ncase++);
        printf("%d\n", ans);
    }

    return 0;
}

另种,先建图在跑spfa:

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 111 * 310;

struct Edge{
    int from, to, dist;
};
struct BellmanFord {
    int n, m;

    int head[maxn];
    int next[maxn * 110];
    int to[maxn * 110];
    int dist[maxn * 110];
    int tot;

    bool inq[maxn];
    int d[maxn];

    void init(int n)
    {
        this->n = n;
        tot = 0;
        memset(head, -1, sizeof(head));
    }
    void AddEdge(int ufrom, int uto, int udist)
    {
        to[tot] = uto;
        dist[tot] = udist;
        next[tot] = head[ufrom];
        head[ufrom] = tot++;
    }
    bool spfa(int ss)
    {
        queue<int>Q;
        memset(inq, 0, sizeof(inq));
        memset(d, 0, sizeof(d));
        d[ss] = 0;
        inq[ss] = 1;
        Q.push(ss);

        while (!Q.empty())
        {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = head[u]; ~i; i = next[i])
//            for (int i = 0; i < G[u].size(); i++)
            {
                int uto = to[i];
                int udist = dist[i];
//                Edge& e = edges[G[u][i]];
                if (d[uto] < d[u] + udist)
                {
                    d[uto] = d[u] + udist;
                    if (!inq[uto])
                    {
                        Q.push(uto); inq[uto] = true;
                    }
                }
            }
        }
        return false;
    }
}bm;

int cost[111], money[111];
int d[111][111];
void floyed(int n)
{
    REP(k, n) REP(i, n) REP(j, n)
    {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    }
}
int n, m, t, s, e;
int ID(int x, int y)
{
    return x * (t + 1) + y;
}

int main ()
{
    int test;
    RI(test);
    int ncase = 1;
    while (test--)
    {
        scanf("%d%d%d%d%d", &n, &m, &t, &s, &e);
        memset(d, 0x3f, sizeof(d));
        for (int i = 0; i < n; i++) d[i][i] = 0;
        for (int i = 0; i < n; i++)
            RI(cost[i]);
        for (int i = 0; i < n; i++)
            RI(money[i]);
        for (int i = 0; i < m; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            d[x][y] = min(d[x][y], z);
            d[y][x] = d[x][y];
        }
        floyed(n);

        int ss = n * (t + 1);
        int ee = ss + 1;
        bm.init(ee + 1);

        for (int i = 0; i < n; i++)
            if (d[s][i] + cost[i] <= t) bm.AddEdge(ss, ID(i, d[s][i] + cost[i]), money[i]);

        bm.AddEdge(ss, ee, 0);

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (i == j || money[i] >= money[j] || d[i][j] == INF) continue;
                for (int tt = 0; tt + d[i][j] + cost[j] <= t; tt++)
                {
                    bm.AddEdge(ID(i, tt), ID(j, tt + d[i][j] + cost[j]), money[j]);
                }
            }
        }

        for (int i = 0; i < n; i++)
            if (d[i][e] != INF) for (int tt = 0; tt + d[i][e] <= t; tt++)
            bm.AddEdge(ID(i, tt), ee, 0);

        bm.spfa(ss);
        int ans = bm.d[ee];
        printf("Case #%d:\n", ncase++);
        printf("%d\n", ans);
    }

    return 0;
}


dp解法:

先拓扑,在dp

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)

typedef long long LL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 111 * 310;

int cost[111], money[111];
int d[111][111];
int dp[111][310];

void floyed(int n)
{
    REP(k, n) REP(i, n) REP(j, n)
    {
        if (d[i][k] == INF || d[k][j] == INF) continue;
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    }
}
int n, m, t, s, e;

int id[111];
int solve()
{
    int ans = 0;
    memset(dp, -1, sizeof(dp));///不能到达的为-1
    for (int i = 0; i < n; i++)
    {
        int ct = d[s][i] + cost[i];
        if (ct <= t)
        {
            dp[i][ct] = money[i];
            if (ct + d[i][e] <= t) ans = max(ans, dp[i][ct]);
        }
    }
    for (int ii = 0; ii < n; ii++)
    {
        int i = id[ii];
        for (int j = 0; j < n; j++)
        {
            if (i == j || money[i] >= money[j] || d[i][j] == INF) continue;
            for (int tt = 0; tt + d[i][j] + cost[j] <= t; tt++)
            {
                if (dp[i][tt] == -1) continue;
                int ct = tt + d[i][j] + cost[j];
                if (dp[j][ct] < dp[i][tt] + money[j])
                {
                    dp[j][ct] = dp[i][tt] + money[j];
                    if (ct + d[j][e] <= t) ans = max(ans, dp[j][ct]);
                }
            }
        }
    }

    return ans;
}

bool cmp(int x, int y)
{
    return money[x] < money[y];
}
int main ()
{
    int test;
    RI(test);
    int ncase = 1;
    while (test--)
    {
        scanf("%d%d%d%d%d", &n, &m, &t, &s, &e);
        memset(d, INF, sizeof(d));
        for (int i = 0; i < n; i++)
            d[i][i] = 0, id[i] = i;
        for (int i = 0; i < n; i++)
            RI(cost[i]);
        for (int i = 0; i < n; i++)
            RI(money[i]);
        for (int i = 0; i < m; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            d[x][y] = min(d[x][y], z);
            d[y][x] = d[x][y];
        }
        floyed(n);
        sort(id, id + n, cmp);
        int ans = solve();
        printf("Case #%d:\n", ncase++);
        printf("%d\n", ans);
    }
    return 0;
}


HDU 4571 Travel in time (SPFA 或 dp),布布扣,bubuko.com

HDU 4571 Travel in time (SPFA 或 dp)

标签:dp   spfa   

原文地址:http://blog.csdn.net/guognib/article/details/25299849

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!