2.2:(贪心)

 

 

一.

1.

Best Cow Line POJ - 3617 

 

给定长度为N(1≤N≤2000)的字符串S,要构造一个长度为N的字符串T。期初,T是一个空串,随后反复进行下列任意操作。

·从S的头部删除一个字符,加到T的尾部

·从S的尾部删除一个字符,加到T的尾部

目标是要构造字典序尽可能小的字符串

Input

· Line 1: 一个整数(integer): N
· Lines 2~+1: Line i+1 contains a single initial ('A'..'Z') of the string in the ith position in the original line

Output

输出时每行最多80个字符

Sample Input

6
A
C
D
B
C
B

Sample Output

ABCBCD
#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

int n;
char s[2005];

int main()
{
	int sum=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		cin>>s[i];
	int a=0,b=n-1;
	while(a<=b)
	{
		bool left=false;
		for(int i=0;i+a<=b;i++)
		{
			if(s[a+i]>s[b-i])
			{
				left=false;
				break;
			}
			else if(s[i+a]<s[b-i])
			{
				left=true;
				break;
			}
		}
		if(left)
			putchar(s[a++]);
		else
			putchar(s[b--]);
		sum++;
		if(sum==80)
		{
			cout<<endl;
			sum=0;
		}
	}	
	return 0;
} 

 2.

Saruman's Army  POJ - 3069 

Saruman the White must lead his army along a straight path from Isengard to Helm’s Deep. To keep track of his forces, Saruman distributes seeing stones, known as palantirs, among the troops. Each palantir has a maximum effective range of R units, and must be carried by some troop in the army (i.e., palantirs are not allowed to “free float” in mid-air). Help Saruman take control of Middle Earth by determining the minimum number of palantirs needed for Saruman to ensure that each of his minions is within R units of some palantir.

Input

The input test file will contain multiple cases. Each test case begins with a single line containing an integer R, the maximum effective range of all palantirs (where 0 ≤ R ≤ 1000), and an integer n, the number of troops in Saruman’s army (where 1 ≤ n ≤ 1000). The next line contains n integers, indicating the positions x1, …, xnof each troop (where 0 ≤ xi ≤ 1000). The end-of-file is marked by a test case with R = n = −1.

Output

For each test case, print a single integer indicating the minimum number of palantirs needed.

Sample Input

0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1

Sample Output

2
4

Hint

In the first test case, Saruman may place a palantir at positions 10 and 20. Here, note that a single palantir with range 0 can cover both of the troops at position 20.

In the second test case, Saruman can place palantirs at position 7 (covering troops at 1, 7, and 15), position 20 (covering positions 20 and 30), position 50, and position 70. Here, note that palantirs must be distributed among troops and are not allowed to “free float.” Thus, Saruman cannot place a palantir at position 60 to cover the troops at positions 50 and 70.

题意:在一条直线上,有n个点。从这n个点中选择若干个,给他们加上标记。对于每一个点,其距离为R以内的区域里必须有一个被标记的点。问至少要有多少点被加上标记。

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

int n,r;
int a[1005];

int  main()
{
	while(scanf("%d%d",&r,&n)!=EOF)
	{
		if(r==-1&&n==-1)
			break;
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		sort(a,a+n);
		int ans=0,i=0;
		while(i<n)
		{
			int p=a[i++];
			while(i<n&&p+r>=a[i])
				i++;
			int s=a[i-1];
			while(i<n&&s+r>=a[i])
				i++;
			ans++;
		}
		cout<<ans<<endl;
	}	
	return 0;
}

3.

Fence Repair POJ - 3253  

现在有一个特殊的数据集,导师希望你按某种条件将它分割成N(1<=N<=20000)个互不相交的子数据集,它们包含的数据量分别是M1,M2 ,…,Mn(1<=Mi<=50000). 分割前的数据集包含的数据量恰好为按要求分割后的所有子数据集的数据量只和。
在导师给的条件下,你一次只能将某个数据集分成两个子数据集,需花费的时间就是这个数据集的数据量。例如导师要求你将一个数据量为32的数据集划分为数据量分别为9、11、12的子数据集。假如你第一步将这个数据集分割为数据量为12和20的子数据集,第二步再将数据量为20的子数据集进一步分割成数据量分别为9和11的数据集。那么完成分割,第一步需要32个单位时间,第二步需要20个单位时间,总共就是52个单位时间。
导师希望你尽快能完成分割任务。请问完成分割任务最少需要多少个单位时间?

Input

第1行:需要分割成的子数据集个数
第(i+1)行:数据量 (1<=i<=N)

Output

完成分割任务最少需要的时间

Sample Input

3
9
12
11

Sample Output

52

思路:贪心+priority_queue 每次取出最小的两根相加然如加入优先队列

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;

typedef long long ll;
int n;
int a[20005];

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	priority_queue<int,vector<int>,greater<int> > que;
	for(int i=0;i<n;i++)
	{
		que.push(a[i]);
	}
	ll ans=0;
	while(que.size()>1)
	{
		ll l1=que.top();
		que.pop();
		ll l2=que.top();
		que.pop();
		que.push(l1+l2);
		ans+=l1+l2;
	}
	cout<<ans<<endl;
	return 0;
}

 二.区间

1.

Cleaning Shift  POJ - 2376 

描述

大表哥分配 N (1 <= N <= 25,000) 只中的一些奶牛在牛棚附近做些清洁。 他总是要让至少一只牛做清洁。他把一天分成T段(1 <= T <= 1,000,000), 第一段是1,最后一段是T 

每只奶牛只在一些时间段有空。奶牛如果选择某一段时间,则必须完成整段时间的工作 

你的任务是帮助FJ安排一些奶牛,使每段时间至少有一只奶牛被安排来做这件事。并且奶牛数应尽可能小。如果不可能办到,输出-1

输入

注意,输入包含多组测试数据,请处理到文件结束
* 第一行:N和T 
* 第二行至N+1行: 每一行包括奶牛能工作的开始和结束时间。闭区间。

输出

*每组数据一行,输出完成清洁所需最少的奶牛数,如果不可能办到,输出-1

样例输入

3 10
1 7
3 6
6 10

样例输出

2

提示

这道题输入数据很多,请用scanf而不是cin 

输入说明 

这里有3只奶牛和10个时间段cow #1 能在时间段1..7工作, cow #2 能在时间段3..6工作, cow #3 能在时间段6..10工作 

输出说明: 

选择 cows #1 和 #3即可,没有更优的方案了 .

思路:先按每个奶牛开始工作的时间先后从小到大排序,然后从下一段可以选的工作中选取结束最晚的时间段

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

typedef pair<int,int> P;
P a[25005];

bool cmp(P a,P b)
{
	return a.first<b.first;
}

int n,T;

int main()
{
	scanf("%d%d",&n,&T);
	for(int i=0;i<n;i++)
		scanf("%d%d",&a[i].first,&a[i].second);
	sort(a,a+n,cmp);
	int t=0,ans=0;	
	bool flag=false;
	for(int i=0;i<n;i++)
	{
		flag=false;
		int temp=t;
		while(a[i].first<=t+1&&i<n)
		{
			temp=max(temp,a[i].second);
			i++;
			flag=true;
		}
		t=temp;
		i--;
		if(!flag)
			break;
		ans++;
		if(t==T)
			break;
	}
	if(!flag||t!=T)
		puts("-1");
	else
		cout<<ans<<endl;
	return 0;
}

 2.

Radar Installation POJ - 1328 

假定海岸线是无限长的直线。陆地位于海岸线的一侧,海洋位于另一侧。每个小岛是位于海洋中的一个点。对于任何一个雷达的安装 (均位于海岸线上),只能覆盖 d 距离,因此海洋中的小岛被雷达安装所覆盖的条件是两者间的距离不超过 d 。 

我们使用卡笛尔坐标系,将海岸线定义为 x 轴。海洋的一侧位于 x 轴上方,陆地的一侧位于下方。给定海洋中每个小岛的位置,并给定雷达安装的覆盖距离,您的任务是写一个程序,找出雷达安装的最少数量,使得所有的小岛都被覆盖。注意:小岛的位置以它的 x-y 坐标表示。 


图 A: 雷达安装的示例输入

输入

输入由多个测试用例组成。每个测试用例的第一行,包含了两个整数 n (1<=n<=1000) 和 d,其中 n 是海洋中小岛的数目,d 是雷达安装的覆盖距离。接下来是 n 行,每行包含了两个整数,表示每个小岛的坐标。每组测试用例之间,以一个空行间隔。 

输入终止于包含两个 0 的一行。

输出

对于每个测试用例,输出一行,包括测试用例的编号,以及雷达安装所需的最小数量。"-1" 个安装,表示该测试用例无解决方案。

示例输入

3 2
1 2
-3 1
2 1

1 2
0 2

0 0

示例输出

Case 1: 2
Case 2: 1

思路:一个海岛左边最远的坐标为left=x-sqrt(d*d-y*y),右边为right=x-sqrt(d*d-y*y),对坐标进行排序,按右边的从小到大排序,如果相等就按左边的从大到小排序。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;

typedef pair<double ,double> P;
P a[1005];
int n,d;

bool cmp(P a,P b)
{
	if(a.second==b.second)
		return a.first>b.first;
	return a.second<b.second;
} 

int main()
{
	int cnt=0;
	while(scanf("%d%d",&n,&d)!=EOF)
	{
		if(!n&&!d)
			break;
		cnt++;
		bool flag=false;
		for(int i=0;i<n;i++)
		{
			double x,y;
			scanf("%lf%lf",&x,&y);
			double left=x-sqrt(d*d-y*y),right=x+sqrt(d*d-y*y);
			if(y>d)
				flag=true;
			a[i].first=left,a[i].second=right;
		}
		if(flag)
		{
			printf("Case %d: -1\n",cnt);
			continue;
		}
		sort(a,a+n,cmp);
		int ans=1;
		double s=a[0].second;
		for(int i=1;i<n;i++)
		{
			if(a[i].first>s)
			{
				ans++;
				s=a[i].second;
			}
		} 
		printf("Case %d: %d\n",cnt,ans);
	}
	return 0;
}

3.

Stall Reservations  POJ - 3190 

这里有N只 (1 <= N <= 50,000) 挑剔的奶牛! 他们如此挑剔以致于必须在[A,B ]的时间内产奶(1 <= A <= B <= 1,000,000)当然, FJ必须为他们创造一个决定挤奶时间的系统.当然,没有牛想与其他奶牛分享这一时光 

帮助FJ做以下事:

  • 使每只牛都有专属时间的最小牛棚数
  • 每只牛在哪个牛棚

也许有很多可行解。输出一种即可,采用SPJ

Input

第一行一个数字 N 

第 2..N+1行: 第 i+1行 描述了i号奶牛挤奶的起止时间

Output

第一行:牛棚最小数量 

Lines 2..N+1: 第 i+1行 描述了i奶牛被安排的牛棚

Sample Input

5
1 10
2 4
3 6
5 8
4 7

Sample Output

4
1
2
3
2
4

Hint

样例解释: 

这里是一种图示 

Time     1  2  3  4  5  6  7  8  9 10

Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>

Stall 2 .. c2>>>>>> c4>>>>>>>>> .. ..

Stall 3 .. .. c3>>>>>>>>> .. .. .. ..

Stall 4 .. .. .. c5>>>>>>>>> .. .. ..

其他的也是可能的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>

using namespace std;

struct node
{
	int s,t,num;
	bool operator < (const node &a) const   //按结束时间从小到大
	{
		if(t==a.t)
			return s>a.s;
		return t>a.t;
	}
}a[50005];
int ans[50005];

bool cmp(node a,node b)   //按开始从小到大
{
	if(a.s==b.s)
		return a.t<b.t;
	return a.s<b.s;
}

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&a[i].s,&a[i].t);
		a[i].num=i;
	}
	sort(a,a+n,cmp);
	int cnt=1; 
	priority_queue<node> que;
	ans[a[0].num]=1;
	que.push(a[0]); 
	for(int i=1;i<n;i++)
	{
		if(que.top().t<a[i].s)
		{
			ans[a[i].num]=ans[que.top().num];
			que.pop();
		}
		else
		{
			cnt++;
			ans[a[i].num]=cnt;
		}
		que.push(a[i]);
	}
	cout<<cnt<<endl;
	for(int i=0;i<n;i++)
		cout<<ans[i]<<endl;
	return 0;
}

三.其他

1.

Yogurt factory POJ - 2393 

奶牛们收购了一家世界著名的酸奶工厂Yucky Yogurt. 在接下来的 N (1 <= N <= 10,000) 周,牛奶和人工的价格每周会波动,以致于第i周需要花公司 C_i (1 <= C_i <= 5,000) 美分来生产一个单位的酸奶. Yucky factory被奶牛们照顾得很好,所以每周可以生产很多单位的酸奶 

Yucky Yogurt 拥有一个仓库,可以以S (1 <= S <= 100)美分每单位每周的价格储存没用的酸奶。神奇的是,酸奶不会变质。而且仓库十分巨大,可以容纳很多牛奶 

Yucky Yogurt每周要交货 Y_i (0 <= Y_i <= 10,000) 单位的酸奶给它的客户。请你帮助奶牛们减少整个 N-week 期间的支出. i周生产的牛奶和之前储存的牛奶都可以用来交i周的货

Input

* 第一行:N and S. 

* 第 2..N+1行:第 i+1 行包括 : C_i 和 Y_i.

Output

* 满足客户需求的最小花费,保证不超过64位整数

Sample Input

4 5
88 200
89 400
97 300
91 500

Sample Output

126900

Hint

输出提示: 
第一周生产200单位,全部售出。第二周生产700单位,售出400,储存300.第三周使用储存的300单位。第四周,生产500单位并全部售出 
注释:
yucky意为难以下咽的

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;
typedef long long ll;
int n,s;
int c[10005],y[10005];

int main()
{
	scanf("%d%d",&n,&s);
	for(int i=0;i<n;i++)
		scanf("%d%d",&c[i],&y[i]);
	for(int i=1;i<n;i++)
	{
		c[i]=min(c[i],c[i-1]+s);
	}
	ll ans=0;
	for(int i=0;i<n;i++)
		ans+=c[i]*y[i];
	cout<<ans<<endl;
	return 0;
}

2.

Packets POJ - 1017 

一家工厂生产的产品规格分为1×1, 2×2, 3×3, 4×4, 5×5, 6×6,高都是h。工厂要把它们包在6×6×h的包装袋中。工厂想让包装数尽可能少。

Input

多组数据。每一行为一组数据。依次是1×1, 2×2, 3×3, 4×4, 5×5, 6×6的产品的个数。 输入数据由6个0结束。

Output

对于每组数据,输出包装所有产品所需最少包装袋数量

Sample Input

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

Sample Output

2 
1
2 

思路:先处理大块的,在处理小块的

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

int a[10];
int num[4]={0,5,3,1};

int main()
{
	while(1)
	{
		int f=0;
		for(int i=1;i<=6;i++)
		{
			scanf("%d",&a[i]);
			f+=a[i];
		}
		if(!f)
			break;
		int ans=a[6]+a[5]+a[4]+(a[3]+3)/4;
		int sum2=a[4]*5+num[a[3]%4];
		if(a[2]>sum2)
			ans+=(a[2]-sum2+8)/9;
		int sum1=ans*36-a[6]*36-a[5]*25-a[4]*16-a[3]*9-a[2]*4;
		if(a[1]>sum1)
			ans+=(a[1]-sum1+35)/36;
		cout<<ans<<endl;
	}
	return 0;
}

3.

Allowance  POJ - 3040 

作为创纪录的牛奶生产的奖励,农场主约翰决定开始给Bessie奶牛一个小的每周津贴。FJ有一套硬币N种(1≤N≤20)不同的面额,每枚硬币是所有比他小的硬币面值的倍数,例如1美分硬币、5美分硬币、10美分硬币和50美分硬币。使用这些硬币,FJ每周至少给Bessie C(1 <= C <=100000000)美分。请你计算他最多能给Bessie几周

Input

* 第一行N 、 C 

* 第 2..N+1行: 硬币价值 V (1 <= V <= 100,000,000) 和数量 B (1 <= B <= 1,000,000)

Output

* 使用这些硬币,每周至少给C美分的前提下的最多周数

Sample Input

3 6
10 1
1 100
5 120

Sample Output

111

Hint


输出提示 
FJ给Bessie 10美分一周;给Bessie 5美分和1美分一百周;给Bessie 两枚5美分十周

思路:如果钱数大于等于C的,那么就直接发出。如果小于 c 的,则从大往小拿,可以等于但是不能大于 c ,如果等于 c 就发出去,如果到最后也没有等于 c 的,再从小往大拿,能发就发,如果反向滚回来还不能发出去的话,剩下的钱就不能发了,直接退出就行。

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

typedef long long ll;
typedef pair<ll,ll> P;
P a[25];
ll n,c;

bool cmp(P a,P b)
{
	return a.first>b.first;
}

int main()
{
	scanf("%lld%lld",&n,&c);
	for(int i=0;i<n;i++)
		scanf("%lld%lld",&a[i].first,&a[i].second);
	sort(a,a+n,cmp);
	ll ans=0;
	bool flag=true;
	for(int i=0;i<n;i++)
	{
		if(a[i].first>=c)
		{
			ans+=a[i].second;
			continue;
		}
		while(a[i].second)
		{
			ll t=0;
			for(int j=i;j<n;j++)
			{
				if(!a[j].second)
					continue;
				while(a[j].second&&t<c)
				{
					t+=a[j].first;
					a[j].second--;
				}
				if(t==c)
				{
					ans++;
					break;
				}
				else if(t>c)
				{
					t-=a[j].first;
					a[j].second++;
				}
			}
			if(t==c)
				continue;
			for(int j=n-1;j>=i;j--)
			{
				if(!a[j].second)
					continue;
				if(t+a[j].second*a[j].first>=c)
				{
					a[j].second-=(c-t+a[j].first-1)/a[j].first;
					t=c;
					ans++;
					break;
				}
				else
				{
					t+=a[j].second*a[j].first;
					a[j].second=0;
				}
			}
			if(t<c)
			{
				flag=false;
				break;
			}
		}
		if(!flag)
			break;
	}
	printf("%lld\n",ans);
	return 0;
}

4.

Stripies  POJ - 1862 

小明在学校里发现了几颗魔法石子。

为什么这么说呢?因为他发现只要把两颗石子放在一起,它们就会自己合并成一颗。
而且经过多次试验之后,小明发现石子的合并过程其实是有规律的(智商+++)。如果质量分别为a,b的石子放在一起,合并出的新石子的质量即为2*sqrt(a*b)

a few minutes later,小明终于把它们合并成了一块石头,然而

真的很重啊啊啊啊啊啊啊啊啊啊!!!!!!!!!!!!!!!!!!!

就这样,学校里多了一块大石头。
全剧终

小明觉得可能是合成顺序的问题,所以他现在想知道最终的这块大石头的质量的最小值是多少(每次合成的时候不一定要取相邻的石子)

Input

第一行输入 N (1 <= N <= 100) :石子的数量. 接下来的 N 行是每颗石子的质量(1<=m<=10000)

Output

输出最小质量。保留至小数点后三位

Sample Input

3
72
30
50

Sample Output

120.000

思路:贪心,每次取出最大的两个

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>

using namespace std;

int n;
double a[105];

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%lf",&a[i]);
	}
		
	priority_queue<double > que;
	for(int i=0;i<n;i++)
	{
		que.push(a[i]);
	
	}
	while(que.size()>1)
	{
		//cout<<que.top()<<endl;
		double a=que.top();
		que.pop();
		double b=que.top();
		que.pop();
		double ans=2*sqrt(a*b);
		que.push(ans);
	}
	printf("%.3lf\n",que.top());
	return 0;
}

5.

Protecting the Flowers POJ - 3262

FJ去砍树,然后和平时一样留了 N (2 ≤ N ≤ 100,000)头牛吃草。当他回来的时候,他发现奶牛们正在津津有味地吃着FJ种的美丽的花!为了减少后续伤害,FJ决定立即采取行动:运输每头牛回到自己的牛棚。 每只奶牛i在离牛棚Ti(1 ≤ Ti ≤ 2,000,000) 分钟路程的地方,每分钟吃掉Di(1 ≤ Di ≤ 100)朵花。FJ使尽浑身解数,也只能一次带回一头奶牛。弄回一头奶牛i需要2*Ti分钟(来回)。由于怕被怼,从FJ决定带回i号奶牛开始,i号奶牛就不会吃花。请你找出被毁坏的花的最小数量 .

Input

第一行:N 
第 2.. N+1: 第i+1行是Ti和Di,

Output

Line 1: 被毁坏花的最少数量。保证结果在64位整数范围内

Sample Input

6
3 1
2 5
2 3
3 2
4 1
1 6

Sample Output

86

Hint

FJ的顺序是: 6, 2, 3, 4, 1, 5.当找回6、2、3、4、1、5时,损失花数量分别为24、28、16、12、6、0 。 24 + 28 + 16 + 12 + 6 = 86.

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

typedef long long ll;
typedef pair<ll,ll> P;
P a[100005];
ll sum[100005];
int n;

bool cmp(P a,P b)
{
	return (a.first*1.0/a.second)<(b.first*1.0/b.second);
}

int main()
{
	scanf("%d",&n);
	ll sum=0;
	for(int i=0;i<n;i++)
	{
		scanf("%lld %lld",&a[i].first,&a[i].second);
		sum+=a[i].second;
	}
	sort(a,a+n,cmp);
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		sum-=a[i].second;
		ans+=sum*a[i].first*2;
	}
	cout<<ans<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值