2013长沙邀请赛 G - Travel in time
题意: Bob将去在长沙旅行,给出了长沙景点的交通图,在两个节点间移动需要时间花费Li。还给出visit每个节点所要的时间花费Ci和Bob对每个节点的满意度Si,此外还有个限制,Bob每次访问的景点必须比上一次访问的景点满意度要高。问:Bob在时间限制T内,从S出发回到E,所能获得的最大满意度。
(节点可以多次经过,可以只经过不参观)
solve:
看到那个要求递增的限制很容易想到DP,
把所有节点(N<100)按Si递增排序,只有在访问了前面的节点才能访问后面的节点。
对于每个节点,保存剩余的时间。
f[i][j] = max(f[k][ j+dist[i][k]+c[i] ] + s[i])
i - 处理到第i个节点; j - 剩余j单位的时间;dist[i][k] - 从节点i到节点k所需要的时间
sad:比赛的时候,在状态数组初始化的地方出错了,一直在检查,从1个小时多点检查到最后结束都没有发现真正的问题所在。
非法状态的处理&状态初始化在这方面之前也犯过类似的错误,但是这次还是没有发现。
在这道题目上卡住,耽误了太多的时间和精力,也错过了在其他题目上突破的机会。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
int c,s,id;
bool operator <(node temp) const
{
return s<temp.s;
}
}a[200];
int dist[110][110];
int S;
void Floyd(int map[110][110],int n)
{
memcpy(dist,map,sizeof(dist));
for (int i = 1;i <= n;i++) dist[i][i] = 0;
for (int k = 1;k <= n;k++)
for (int i = 1;i <= n;i++)
for (int j = 1;j <= n;j++)
if (dist[i][j] > dist[i][k]+dist[k][j])
dist[i][j] = dist[i][k] + dist[k][j];
for (int i = 1;i <= n;i++)
dist[0][i] = dist[S][i];
}
int main()
{
freopen("test.txt","r",stdin);
int W;
cin>>W;
for (int cas = 1;cas <= W;cas++)
{
int N,M,T,E;
cin>>N>>M>>T>>S>>E;
++S,++E;
for (int i = 1;i <= N;i++) scanf("%d",&a[i].c);
for (int i = 1;i <= N;i++)
{
scanf("%d",&a[i].s);
a[i].id = i;
}
static int map[110][110];
memset(map,0x3f,sizeof(map));
for (int i = 1;i <= M;i++)
{
int u,v,l;
scanf("%d%d%d",&u,&v,&l);
++u,++v;
if (l < map[u][v])
map[u][v] = map[v][u]= l;
}
a[0].c = a[0].id = 0;
a[0].s = -1;
sort(a+1,a+N+1);
Floyd(map,N);
if (dist[S][E] > T)
{
printf("Case #%d:\n",cas);
cout<<0<<endl;
continue;
}
int ans = 0;
static int f[110][310];
///!wrong memset(f,0,sizeof(f));
///!初始化出错,没有排除掉非法状态,当时只考虑使得f[0][i](i<T)=0,这时赋值为0贬低了状态值,不会导致错误;
///!但是没有考虑到f[i][..](i>0),此时却上扬了状态值,这个一定会导致错误的。
memset(f,-0x3f,sizeof(f));
f[0][T] = 0;
for (int i = 1;i <= N;i++)
{
int u = a[i].id;
for (int j = 0;j <= T;j++)
{
for (int k = 0;k < i;k++) if (a[k].s < a[i].s)
{
int v = a[k].id;
int tmp = j+dist[v][u]+a[i].c;
if (tmp <= T) f[i][j] = max(f[i][j],f[k][tmp]+a[i].s);
}
if (j >= dist[u][E]) ans = max(ans,f[i][j]);
}
}
printf("Case #%d:\n",cas);
cout<<ans<<endl;
}
}
4
4 4 22 0 0
1 1 1 1
5 7 9 12
0 1 10
1 3 10
0 2 10
2 3 10
5 4 1 4 4
1 1 1 1 1
5 7 9 12 15
0 1 10
1 3 10
0 2 10
2 3 10
2 1 32 0 1
1 1
10 5
0 1 10
5 4 41 0 4
1 1 1 1 1
5 10 15 20 25
0 1 10
1 2 10
2 3 10
3 4 10
答案:
Case #1:
14
Case #2:
15
Case #3:
15
Case #4:
25
f[0][T] = 0;其他的值应该是什么?其他的值可以初始化为0吗?
--! 可以,f[0][i] (i<T) 是把状态值给贬低了,不会影响最后的结果。
--!不可以,没有考虑其他的非法状态,比如f[i][T](i>0),这样会把状态值给上扬,一定会导致错误。
正确:f[0][T] = 0;f[other] = -INF;
初始化的时候,1.把合法的状态赋值为相应值;2.非法状态要么标志出来,要么赋值为不可能值。切记不要偷懒赋值为一个合法值,因为这样可能会同时贬低某些状态值和上扬某些状态值,而没有察觉。
越贴近事实就越准确