贪心算法题解(2)

A. 基站安装

Description

从前有一个一望无际的海滩,海滩后面是陆地,前面是广阔的大海。海中有很多小岛(可以用一个点表示)。现在海滩上需要安装一些基站(海滩上的任意位置)这样岛上的居民就能用手机通话了,所有的基站的覆盖距离都是d,在距离d范围内的小岛都能收到基站发送的信号。

img

我们用笛卡尔坐标系来表示这个问题,定义x轴为海滩,x轴上方是大海,下方是陆地。现给出每个小岛的位置(用x-y坐标表示)和基站的覆盖范围d,你的任务就是写一个程序,计算出可以覆盖所有的小岛,至少需要在海滩上安装多少基站?

Input

输入包含多组数据。对每组数据,第一行包含两个整数n(1 <= n <= 1000)和d,n代表小岛数量,d代表基站的覆盖距离。接下来有n行,每行包含两个整数,表示小岛的位置坐标。输入n=0,d=0时退出。

Output

对每组数据,输出包含数据组数,格式如sample,后跟最少需要安装的基站数,如果无解,输出-1。

Sample Input

3 2
1 2
-3 1
2 1
1 2
0 2
1 -2
0 2
0 0

Sample Output

Case 1: 2
Case 2: 1
Case 3: -1

Answer

#include <bits/stdc++.h>
using namespace std;

#define MAX 1001
struct TPoint {
	int x;
	int y;
};
struct TLimit {
	double dFrom;
	double dTo;
};
TPoint tIsland[MAX];
TLimit tSeg[MAX];
void vInput(int nN);
bool bcheck(int nN,int nD);
void vOut(int nC,int nOut);
void vSort(int nN);
bool bCmp(const TLimit &tA,const TLimit &tB);
int nGetAns(int nN);
int main() {
	int nCase;
	int nAns;
	int nLands,nDist;
	nCase=1;
	while(cin>>nLands>>nDist) {
		if((0==nLands)&&(0==nDist)) {
			return 0;
		} else {
			vInput(nLands);
			if(bcheck(nLands,nDist)) {
				vSort(nLands);
				nAns=nGetAns(nLands);
			} else {
				nAns=-1;
			}
			vOut(nCase,nAns);
			nCase++;
		}
	}
	return 0;
}
void vInput(int nN) {
	int i;
	for(i=1; i<=nN; i++) {
		cin>>tIsland[i].x>>tIsland[i].y;
	}
}
bool bcheck(int nN,int nD) {
	int i;
	for(i=1; i<=nN; i++) {
		if(tIsland[i].y>nD) {
			return false;
		}
		tSeg[i].dFrom=tIsland[i].x-sqrt(1.0*nD*nD-1.0*tIsland[i].y*tIsland[i].y);
		tSeg[i].dTo=tIsland[i].x+sqrt(1.0*nD*nD-1.0*tIsland[i].y*tIsland[i].y);
	}
	return true;
}
void vOut(int nC,int nOut) {
	cout << "Case " << nC << ": " << nOut << endl;
}
void vSort(int nN) {
	sort(&tSeg[1],&tSeg[nN+1],bCmp);
}
bool bCmp(const TLimit &tA,const TLimit &tB) {
	return (tA.dFrom<tB.dFrom);
}
int nGetAns(int nN) {
	int nRet;
	int i;
	double dTemp;
	nRet=1;
	dTemp=tSeg[1].dTo;
	for(i=2; i<=nN; i++) {
		if(tSeg[i].dFrom>dTemp) {
			nRet++;
			dTemp=tSeg[i].dTo;
		} else {
			if(dTemp>tSeg[i].dTo) {
				dTemp=tSeg[i].dTo;
			}
		}
	}
	return nRet;
}

B. 打包问题

Description

一个工厂把产品包装在正方形的箱子里,尺寸有1×1,2×2,3×3,4×4,5×5,6×6六种,高度为h。产品最终总是捆扎成高度为h的6×6的包裹箱子送到客户手里,因为客户希望包裹箱子越少越好。请你编写一个程序计算最少需要多少只包裹箱子才能把客户买的产品送完。

Input

输入包含多组数据。每组数据有一行,包含6个整数,用空格隔开,分别代表1×1的产品、2×2的产品……6×6的产品的个数。输入6个0时退出。

Output

每组数据输出一行,输出最少需要的包裹箱子数。

Sample Input

0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0

Sample Output

2
1

Answer

#include <bits/stdc++.h>
using namespace std;

int nBox[7];
int nBigBox;
void vInit();
void vPack();
void vOut();
void vInput();
int main() {
	int nSum;
	vInput();
	nSum=nBox[6]+nBox[5]+nBox[4]+nBox[3]+nBox[2]+nBox[1];
	while(nSum!=0) {
		vInit();
		vPack();
		vOut();
		vInput();
		nSum=nBox[6]+nBox[5]+nBox[4]+nBox[3]+nBox[2]+nBox[1];
	}
	return 0;
}
void vInit() {
	nBigBox=0;
}
void vPack() {
	int n1X1,n2X2;
	int nTemp;
	n1X1=0;
	n2X2=0;
	nBigBox+=nBox[6];
	nBigBox+=nBox[5];
	nBigBox+=nBox[4];
	n2X2+=nBox[4]*5;
	nBigBox+=nBox[3]/4;
	nTemp=nBox[3]%4;
	if(nTemp>0) {
		nBigBox++;
		switch(nTemp) {
			case 1:
				n2X2+=5;
				break;
			case 2:
				n2X2+=3;
				break;
			case 3:
				n2X2+=1;
				break;
		}
	}
	if(nBox[2]>n2X2) {
		nBigBox+=(nBox[2]-n2X2)/9;
		nTemp=(nBox[2]-n2X2)%9;
		if(nTemp>0) {
			nBigBox++;
		}
	}
	n1X1=nBigBox*36-nBox[6]*36-nBox[5]*25-nBox[4]*16-nBox[3]*9-nBox[2]*4;
	if(nBox[1]>n1X1) {
		nBigBox+=(nBox[1]-n1X1)/36;
		nTemp=(nBox[1]-n1X1)%36;
		if(nTemp>0) {
			nBigBox++;
		}
	}
}
void vOut() {
	cout << nBigBox << endl;
}
void vInput() {
	int i;
	for(i=1; i<=6; i++) {
		cin >> nBox[i];
	}
}

C. 上课问题

Description

题目大意:北大的很多研究生住在万柳校区,他们每天要坐公交或骑车去4.5公里远的燕园上课。由于北京的交通很烂(我想也是很烂),许多同学选择骑车去上课。查理同学和其他同学的骑车习惯不同,其他同学都是以固定的速度骑行,查理则是跟某个MM一起,这样就不会觉得无聊。当查理出发的时候,他会寻找一个MM作伴去燕园。如果找到了PLMM,他就会和她一起,否则就继续物色。在去燕园的路上,如果有某个MM速度比较快,超过他了,他就会丢下身边的MM去追那个更快的MM,然后和她一起去燕园。我们假设查理出发的时刻为0,现给出很多MM的出发时间和速度,你来计算一下查理什么时候能到燕园呢?

Input

包含多组数据。每组数据第一行以个整数N(1<=N<=10000),代表MM数,N=0时退出,接下来有N行,每行代表一个MM的骑行信息。格式:Vi ,Ti。0 < Vi <= 40,代表骑车速度(km/h),Ti是该MM的出发时间(s),Ti可能小于0。

Output

每行输出代表一组数据。输出查理到达燕园的时间,不满1秒的按1秒算。

Sample Input

4
20 0
25 -155
27 190
30 240
2
21 0
22 34
0

Sample Output

780
771

Answer

#include <bits/stdc++.h>
using namespace std;

int nTime[10005];
int nNowTime;
int nInput(int nN);
void vSort(int nN);
void vOut(int nN);
int main() {
	int nNum,nCnt;
	cin>>nNum;
	while(nNum != 0) {
		nCnt = nInput(nNum);
		vSort(nCnt);
		vOut(nCnt);
		cin>>nNum;
	}
	return 0;
}
int nInput(int nN) {
	double dTime;
	int nV,nT,nCnt=0,nArrive;
	for(int i=0; i<nN; i++) {
		cin>>nV>>nT;
		if(nT<0) {
			continue;
		} else {
			dTime = (double) 4500/nV/1000*3600;
			nArrive = ceil(dTime)+nT;
			nTime[nCnt++] = nArrive;
		}
	}
	return nCnt;
}
void vSort(int nN) {
	sort(nTime,nTime+nN);
}
void vOut(int nN) {
	cout<<nTime[0]<<endl;
}

D. 高速公路维修问题

Description

最近十几年,我们国家的高速公路发展迅速,覆盖全国的高速公路里程数逐年增加,由于建设速度快,也带来了一个问题,那就是高速公路的建设质量令人担心,但并不是所有的问题都是由建设质量一方面造成的,长期的超载超限运营也会造成路基路面的损坏,我们常常看到有些路段的路面坑坑洼洼的,一旦路面出现问题,很有可能造成严重的交通事故,因此需要修复,高速公路的修复有很多特殊性,比如一个小的坑洼,不是补一补就可以的,需要在坑洼的附近一段里面都挖掉重新铺设材料,哪怕是只有一个小的坑洼也一样,甚至一个小洼地的修补和很多个连在一起的洼地修复的成本是一样的。现在我们把一个最小的修复长度算作一个修补单位,在这个长度范围内一个洼地和多个洼地的修补成本是一样的,现在给你在一条高速公路上所有的洼地的位置(我们假定起点为高速公路的一端,另一端足够长),请你帮忙写个程序计算一下,如要修复所有的洼地,最少需要多少个修补单位。

Input

本问题有多组测试数据,每一组数据有两行,第一行有两个整数N和L(中间用空格分隔),分别表示N(0<=N<=1000)个洼地和修补单位的长度L(0<L<=100)。第二行共有N个整数a1,a2…an(用空格分隔),分别表示N个洼地的位置(0<=ai<=20000)。

Output

对于每组输入只有一行输出,即最少需要的修补单位个数。

Sample Input

2 50
10 61
4 50
10 59 60 61

Sample Output

2
2

Answer

#include <bits/stdc++.h>
using namespace std;

int nIndex[10001];
void vInput(int nN);
void vSort(int nN);
int nCount(int nN,int nL);

int main() {
	int nRet;
	int nNum,nLen;
	while(cin>>nNum>>nLen) {
		if(nNum == 0) {
			cout<<0<<endl;
			continue;
		}
		vInput(nNum);
		vSort(nNum);
		nRet = nCount(nNum,nLen);
		cout<<nRet<<endl;
	}

	return 0;
}

void vInput(int nN) {
	for(int i=0; i<nN; i++) {
		cin>>nIndex[i];
	}
}
void vSort(int nN) {
	sort(nIndex,nIndex+nN);
}
int nCount(int nN,int nL) {
	int nRet,nTemp;
	nTemp = nIndex[0]+nL;
	nRet=1;
	for(int i=1; i<nN; i++) {
		if(nIndex[i]>nTemp) {
			nRet++;
			nTemp = nIndex[i]+nL;
		}
	}
	return nRet;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值