[ZOJ 3358] Green Dam Girl [动态规划+Floyd]

26 篇文章 0 订阅
18 篇文章 0 订阅

GDG破产了,但是她有一些追随者,追随者会资助她一些钱。她在每个追随者的房间住一晚上就可以得到一些钱,在第i个人的房间住的第一个晚上可以获得ai,如果一直不离开这个房间的话,第二个晚上可以获得bi,之后每个晚上都可以获得ci(这题目真没节操...)。每天白天她都可以移动,但因为她有一些行李,所以她无法自己从某个房间移动到其他房间,但是第i个房间的追随者可能会允许以收一定的钱为代价帮她把行李搬到某个特定的其他的房间。移动没有次数限制,即一天可以移动多次,并且可以移动回最原来的房间,以获得ai的钱。最开始GDG在0号房间。问她在第l个晚上之前最多可以得到多少钱?

数据范围:最多100个房间,最多100天,每个钱数都不超过10^4所以总共不会超过int。

首先Floyd求从任意房间到任意房间的移动代价。

然后dp求解,定义状态dp[i][j]为第i天结束时在j号房间所能够达到的最大钱数。每次转移的时候先枚举这天所有的移动的可能性(100*100),计算出第i天的白天移动到第i号房间后所能达到的最大钱数,然后枚举在这个房间呆的天数。

#include <cstdio>
#include <cstring>

int n,d;
int dis[100][100],dis2[100];
int a[100],b[100],c[100];
int dp[101][100];

inline void update(int &a,int b) {
	if (a==-1||a<b) a=b;
}

int main() {
	int i,j,k,m,x,y;
	while (scanf("%d%d",&n,&d)!=EOF) {
		memset(dis,-1,sizeof(dis));
		for (i=0;i<n;i++) {
			scanf("%d%d%d",&a[i],&b[i],&c[i]);
			scanf("%d",&m);
			for (j=0;j<m;j++) {
				scanf("%d%d",&x,&y);
				dis[i][x]=y;
			}
		}
		for(k=0;k<n;k++)
			for (i=0;i<n;i++)
				for (j=0;j<n;j++) 
					if (dis[i][k]!=-1&&dis[k][j]!=-1&&(dis[i][j]==-1||dis[i][j]>dis[i][k]+dis[k][j]))
						dis[i][j]=dis[i][k]+dis[k][j];
		memset(dp,-1,sizeof(dp));
		dp[0][0]=0;
		update(dp[1][0],a[0]);
		update(dp[2][0],a[0]+b[0]);
		int tmp=a[0]+b[0]+c[0];
		for (k=3;k<d;k++) {
			update(dp[k][0],tmp);
			tmp+=c[0];
		}
		for (i=1;i<d-1;i++) {
			memset(dis2,-1,sizeof(dis2));
			for (j=0;j<n;j++)
				if (dp[i][j]!=-1) 
					for (k=0;k<n;k++) {
						if (dis[j][k]>=0) {
							int tmp=dp[i][j]-dis[j][k];
							if (tmp>=0) update(dis2[k],tmp);
						}
					}
			for (j=0;j<n;j++) {
				if (dis2[j]!=-1) {
					update(dp[i+1][j],dis2[j]+a[j]);
					update(dp[i+2][j],dis2[j]+a[j]+b[j]);
					int tmp=dis2[j]+a[j]+b[j]+c[j];
					for (k=i+3;k<d;k++) {
						update(dp[k][j],tmp);
						tmp+=c[j];
					}
				}
			}
		}
		int ans=-1;
		for (j=0;j<n;j++) {
			update(ans,dp[d-1][j]);
		}
		printf("%d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值