HDU 4571 Travel in time (SPFA 或 dp)

来源:互联网 发布:算法基础 豆瓣 编辑:程序博客网 时间:2024/06/13 04:47

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;}


0 0
原创粉丝点击