题意:有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; }