为了庆祝奶牛Bessie的生日,Farmer John给了她一块最好的牧场,让她自由的享用。
牧场上一共有 \(N\) 块草地 \((1≤N≤1000)\),编号为\(1...N\),每块草地上牧草的质量都不同。
如果Bessie吃掉的草地上牧草质量为 \(Q\),她可以获得 \(Q\) 单位的能量。
每块草地最多和\(10\)块草地有相连的道路,在相连的两个草地之间走动需要消耗E单位的能量 \((1≤E≤1,000,000)\)。
Bessie可以从任意一块草地开始吃草,并且想要在获得了最多能量的时候停止。
有点遗憾的,Bessie是一头挑食的奶牛,一旦她吃过了一定质量的牧草,她就不会再吃相同或更低质量的牧草!但是她仍然很愿意路过某些草地,而不吃它们。实际上,她发现路过一块高质量的草地而不吃它,等一下返回再去享用,有时会更有利!
请帮忙计算Bessie能够获得的能量的最大值。
1行:包含两个整数 \(N\) 和 \(E\)。
接下来N行:每行描述一块草地,首先两个整数 \(Q\) 和 \(D\),分别表示草地上牧草的质量(范围1…1,000,000)和相连的草地数量。然后 \(D\)个整数表示相连的草地。
输出Bessie能够获得的能量的最大值。
5 2 4 1 2 1 3 1 3 4 6 2 2 5 5 2 2 5 2 2 3 4
7
读题完毕,我们发现决定答案的因素主要有二
奶牛到达不同点的时候的点权和(升序)
走路径所花费的精力 \(E\)
起初可能觉得处理升序是最麻烦的点,实则不然,发现点权可以通过从小到大排序解决,处理的问题就在如何快速求出从一点到另一个点花费的精力 \(E\)
点数非常小,暴力解决问题,即\(BFS\)预处理出两点之间的精力
状态 \(F[i]\) 表示到达前 \(i\) 个点时的最大精力,由于提前排序,所以可以看作一个简单的 \(01\) 背包
状态转移方程:\(F[i]=max(F[i],F[i-dis_{i-j}]+w[i])\)
#include<bits/stdc++.h> #define int long long using namespace std; const int N=2010,M=5e4+10; int h[N],idx,ne[M],e[M],dis[N][N],n,E,res=-1,f[N]; bool st[N]; struct node {int w,num;}a[M]; bool cmp(node a,node b) {return a.w<b.w;} void add(int u,int v) {ne[++idx]=h[u],e[idx]=v,h[u]=idx;} void bfs(int u) { queue<int> q; memset(st,0,sizeof st); dis[u][u]=0,st[u]=1,q.push(u); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=h[now];~i;i=ne[i]) { int j=e[i]; if(!st[j]) st[j]=1,dis[u][j]=dis[u][now]+E,q.push(j); } } return ; } signed main() { scanf("%lld%lld",&n,&E); memset(h,-1,sizeof h);memset(dis,0x7f,sizeof dis); for(int i=1;i<=n;i++) { int x; scanf("%lld%lld",&a[i].w,&x); a[i].num=i; while(x--) { int v; scanf("%lld",&v); add(i,v); } } sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) bfs(i); for(int i=0;i<=n;i++) dis[0][i]=0; for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) f[i]=max(f[i],f[j]-dis[a[j].num][a[i].num]+a[i].w); res=max(res,f[i]); } printf("%lld",res); return 0; }