类型:图论、动态规划
题意:
n点m边的无向图,每个点有时间权值和满足度权值。在T时间内,从起点S走到终点E。每个点可以选择路过,也可以选择进入,进入点之后增加满足度。要求进入点的满足度必须严格大于上一次进入的点的满足度。求总满足度的最大值。
分析:
一开始按照题目的意思进行BFS,怎么讲怎么搜,但是由于状态太多,导致MLE和TLE。
后来想到,一个点如果不进入,那么在这题路径上,这个点可以直接忽略的,所以可以Floyd求出点之间的最短距离,然后再次BFS,仍然TLE。
后来考虑采用DP,设置状态dp(u,s,k),表示到u点,当前点满足度为s,还剩k时间。
采用记忆化搜索即可。
代码:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int M=128;
int t,n,m,T,S,E,u,v,w,ans;
int s[M],c[M];
class Floyd { ///多源最短路o(MV^3)
typedef int typec;///边权的类型
static const int MV=128;///点的个数
int n,i,j,k;
typec mat[MV][MV];
public:
void init(int tn) { ///传入点的个数,下标0开始
n=tn;
for(i=0; i<n; i++)
for(j=0; j<n; j++)
mat[i][j]=i==j?0:inf;
}
void add(int u,int v,typec w) {
mat[u][v]=min(mat[u][v],w);
}
void solve() {
for(k=0; k<n; k++)
for(i=0; i<n; i++)
for(j=0; j<n; j++)
mat[i][j]=min(mat[i][j],mat[i][k]+mat[k][j]);
}
typec getdist(int x,int y) {
return mat[x][y];
}
} floyd;
int dp[123][123][345];
int dfs(int u, int v, int k) {
if (floyd.getdist(u,E) > k) return -inf;
if (~dp[u][v][k]) return dp[u][v][k];
dp[u][v][k] = 0;
for (int i=0; i<n; i++) {
if (s[i] <= v) continue;
dp[u][v][k] = max(dp[u][v][k], dfs(i, s[i], k-c[i]-floyd.getdist(u,i))+s[i]);
}
return dp[u][v][k];
}
int main() {
while(~scanf("%d",&t)) {
int cas=1;
while(t--) {
scanf("%d%d%d%d%d",&n,&m,&T,&S,&E);
for(int i=0; i<n; i++) {
scanf("%d",&c[i]);
}
for(int i=0; i<n; i++) {
scanf("%d",&s[i]);
}
floyd.init(n);
while(m--) {
scanf("%d%d%d",&u,&v,&w);
floyd.add(u,v,w);
floyd.add(v,u,w);
}
floyd.solve();
mt(dp,-1);
int ans = dfs(S,0,T);
if(ans<0) {
printf("Case #%d:\n0\n",cas++);
} else {
printf("Case #%d:\n%d\n",cas++,ans);
}
}
}
return 0;
}