大概题意: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
//#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;
}