Treasure Map DP

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

猜你喜欢

转载自blog.csdn.net/qq_41231363/article/details/80140269