题意:有n个金矿,每个金矿有一个最开始的产量,同时产量会随着天数增加而减少,金矿之间有一些边,边权是行走需要的天数,人在金矿只等待一天,但是可以离开后再返回这个金矿,问最大可以收集多少金子。
思路:最开始以为需要预处理出来可达矩阵,点数为1000,很明显会T,但是后来发现想多了。。。令dp[i][j] 表示 在第i天第j个金矿可以取得的金子的最大值,dp[i][j]就可以由与j相邻的金矿并且在规定时间内是可达的 再并且 这个点是已经更新过的(因为这个条件当时忘记考虑了wa了好多发) 得到。枚举天数即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1005*2;
int n,m;
int val[maxn],ddd[maxn];
int mp[maxn][maxn];
int dp[maxn][maxn];
vector<int>mm[maxn];
int cost(int x,int t)
{
return max(val[x]-t*ddd[x],0);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
for(int i=0;i<=n;i++){
mm[i].clear();
}
memset(mp,0x3f,sizeof(mp));
int maxe=-1;
for(int i=1;i<=n;i++){
scanf("%d%d",&val[i],&ddd[i]);
maxe=max(maxe,val[i]);
}
maxe+=10;
for(int i=1;i<=m;i++){
int t1,t2,t3;
scanf("%d%d%d",&t1,&t2,&t3);
mp[t1][t2]=t3;
mp[t2][t1]=t3;
mm[t1].push_back(t2);
mm[t2].push_back(t1);
}
memset(dp,0,sizeof(dp));
dp[1][1]=val[1];
int sum=dp[1][1];
for(int i=2;i<=maxe;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<mm[j].size();k++){
int now=mm[j][k];
if(i-mp[now][j]>=1&&dp[i-mp[now][j]][now]&&(i-mp[now][j])){
dp[i][j]=max(dp[i][j],dp[i-mp[now][j]][now]+cost(j,i-1));
sum=max(sum,dp[i][j]);
// printf("fuck dp[%d][%d]==%d j==%d now==%d day==%d\n",i,j,dp[i][j],j,now,mp[j][now]);
}
}
}
}
printf("%d\n",sum);
}
return 0;
}