HDU 4571 Travel in time (SPFA 或 dp)

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)

时间: 2024-08-10 20:14:07

HDU 4571 Travel in time (SPFA 或 dp)的相关文章

hdu 4571 Travel in time (Floyd+记忆化搜索)

Travel in time Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1853    Accepted Submission(s): 374 Problem Description Bob gets tired of playing games, leaves Alice, and travels to Changsha alo

hdu 1561The more, The Better(树形dp&amp;01背包)

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4949    Accepted Submission(s): 2918 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝

HDU 4114 Disney&#39;s FastPass (状压DP)

题意:给定 n 个区域,然后给定两个区域经过的时间,然后你有 k 个景点,然后给定个每个景点的区域和有票没票的等待时间,从哪些区域能够得到票,问你从景点1开始,最后到景点1,而且要经过看完这k个景点. 析:一个状压DP,dp[s1][s2][i] 表示已经访问了 s1 中的景点,拥有 s2 的票,当前在 i 区域,然后两种转移一种是去下一个景点,另一种是去下一个区域拿票.当时输入,写错了,卡了好长时间.... 代码如下: #pragma comment(linker, "/STACK:10240

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12341   Accepted: 7204 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

hdu 4863 Centroid of a Tree 树dp

代码来自baka.. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vecto

HDU 1503 Advanced Fruits (LCS,DP)

题意:给你两字符串s1,s2,用最短的字符串表示他们(公共字串输出一次). Sample Input apple peach ananas banana pear peach Sample Output appleach bananas pearch dp[i][j] : 第一个字符串的前 i 个 ,和第二个字符串的前 j 个最短组合的长度 . pre[i][j] : 第一个字符串的第 i 个 ,和第二个字符串的第 j 个字符的状态. #include<cstdio> #include<

HDU 4901 The Romantic Hero(二维dp)

题目大意:给你n个数字,然后分成两份,前边的一份里面的元素进行异或,后面的一份里面的元素进行与.分的时候按照给的先后数序取数,后面的里面的所有的元素的下标一定比前面的大.问你有多上种放元素的方法可以使得前面异或的值和后面与的值相等. dp[x][y] 表示走到第x步,得到y这个数字一共有多少种方法. 但是需要注意这里得分一下,不能直接用dp数组存种数,你需要分一下从上一层过来的次数,和这一层自己可以到达的次数.然后取和的时候前后两个集合的种数进行乘法,注意边乘边取余. 顺便给一组数据: 4 3

hdu 1024 Max Sum Plus Plus(DP)

转移方程dp[i][j]=Max(dp[i][j-1]+a[j],max(dp[i-1][k] ) + a[j] ) 0<k<j 此链接中有详解点击打开链接 #include<stdio.h> #include<algorithm> #include<iostream> using namespace std; #define MAXN 1000000 #define INF 0x7fffffff int dp[MAXN+10]; int mmax[MAXN