POJ1042 Gone Fishing & POJ3069 Saruman's Army题解

POJ 1042 Gone Fishing

题意简述:
给定鱼塘个数、钓鱼时间,以及每个鱼塘内单位时间内能钓到的鱼的数量和时间的关系,以及从一个池塘到另一个池塘的花费时间。请给出一个最优策略,使得能钓到最多的鱼,且尽量在靠前的鱼塘花费更多的时间。(更多细节请看原题面)

解题思路:
本题采用贪心策略。如果我们在前k个池塘钓鱼,那么由于路上花费时间确定,那么就相当于剩下的时间我们就可以自由分配在前k个池塘上。于是就相当于没有了“单向前进”这一限制,我们每次就可以“自由的”选择当前能掉出的鱼数量最大的池塘。
于是我们枚举终点,即只在前1个池塘钓鱼、只在前2个池塘钓鱼、…、只在前n个池塘钓鱼,找出这些不同的阶段中钓鱼数量最大的那一个,并输出答案。

注意:如果所有池塘的鱼都被钓完,那么应当将所有剩下的时间都花费在第一个池塘。还需注意若钓鱼数相同,需要在靠前的池塘花费更多时间。记得初始化

代码示例:

#include<cstdio>
#include<algorithm>
#include<cstring>
int n,h;
int f[30],d[30],t[30],f2[30];
int ans[30],Stay[30],Stay2[30];
int getRes(int h2,int ed){
	int mx = 0,pos,res = 0;
	memset(Stay,0,sizeof Stay);
	for(int i = 1;i <= ed;i++) f2[i] = f[i];
	while(h2 >= 5){
		mx = 0;
		for(int i = 1;i <= ed;i++){
			if(mx < f2[i]){
				mx = f2[i]; pos = i;
			}
		}
//		printf("%d %d %d %d %d\n",pos,f2[pos],res,h2,mx);
		if(mx == 0) break;
		h2 -= 5; res += f2[pos];
		f2[pos] -= d[pos]; Stay[pos] += 5;	
	}
	if(h2 > 0) Stay[1] += h2;
//	printf("%d %d\n\n",h2,res);
	return res;
}
void solve(){
	int h2 = h,ans = 0;
	memset(Stay2,0,sizeof Stay2);
	for(int i = 1;i <= n;i++){
		int tmp = getRes(h2,i);	
		if(ans <= tmp){
			bool flag = true;
			if(ans == tmp) for(int j = 1;j <= n;j++) if(Stay2[j] > Stay[j]) flag = false;
			ans = tmp;
			if(flag) for(int j = 1;j <= n;j++) Stay2[j] = Stay[j];
		}
		h2 -= 5*t[i];
	}
	for(int i = 1;i < n;i++) printf("%d, ",Stay2[i]);
	printf("%d\n",Stay2[n]);
	printf("Number of fish expected: %d\n\n",ans);
}
int main(){
	while(true){
		scanf("%d",&n);
		if(n == 0) break;
		scanf("%d",&h);h*= 60;
		for(int i = 1;i <= n;i++) scanf("%d",f+i);
		for(int i = 1;i <= n;i++) scanf("%d",d+i);
		for(int i = 1;i < n;i++) scanf("%d",t+i);
		solve();
	}
	return 0;
}
POJ 3069 Saruman’s Army

题意简述:
给定x轴上的若干点,这些点可能重叠,然后给定若干“雷达”,雷达的覆盖半径为R,要求花费最少的雷达覆盖所有的点(雷达只能放在所给的坐标上)。

解题思路:
将所有需要覆盖的坐标升序排列,对于最靠前的一个点,从该点出发向后找最后一个距离该点小于R的点,并将雷达放在其上。并将雷达范围内所有点标记,重复这一操作直到所有点都被覆盖。

代码示例:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
const int N = 1100;
int x[N],vis[N];
int r,n;
void solve(){
	int ans = 0;
	std::sort(x+1,x+n+1);
	for(int i = 1;i <= n;i++){
		if(vis[x[i]]) continue;
		int pos = i;
		for(int j = i+1;j <= n;j++){
			if(x[j]-x[i] <= r) pos = j;
			else break;
		}
		for(int j = i;j <= n;j++) if(abs(x[j]-x[pos]) <= r) vis[x[j]] = 1;
		ans++;
	}
	printf("%d\n",ans);
}
int main(){
	while(~scanf("%d%d",&r,&n)){
		if(r == -1 && n == -1) break;
		memset(vis,0,sizeof vis);
		for(int i = 1;i <= n;i++) scanf("%d",x+i);
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迷亭1213

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值