{2018.5.8}荀(gou)彧(huo)的贪心初步小结

在于递归和递推做了几个晚上的斗争之后;

荀彧同学来到了贪心算法;

讲真,有时候题目看懂了;

但是!

一点思路都没有;

内心绝望;

在各位大佬的帮助下;

荀彧同学算是稍微学会了一点吧;

在这里做个小结;

1>修理牛棚

上题目:

题目描述

在一个暴风雨的夜晚,农民约翰的牛棚的屋顶、门被吹飞了。 好在许多牛正在度假,所以牛棚没有住满。 有些牛棚里有牛,有些没有。 所有的牛棚有相同的宽度。 自顶遗失以后,农民约翰必须尽快在牛棚之上竖立起新的木板。 他的新木材供应者将会供应他任何他想要的长度,但是供应者只能提供有限数目的木板。 农民约翰想将他购买的木板总长度减到最少。 给出 M(1<= M<=50),可能买到的木板最大的数目;S(1<= S<=200),牛棚的总数;C(1 <= C <=S) 牛棚里牛的数目,和牛所在的牛棚的编号stall_number(1 <= stall_number <= S),计算拦住所有有牛的牛棚所需木板的最小总长度。 输出所需木板的最小总长度作为的答案。

输入格式

第 1 行: M , S 和 C(用空格分开) 第 2 到 C+1行: 每行包含一个整数,表示牛所占的牛棚的编号。

输出格式

单独的一行包含一个整数表示所需木板的最小总长度。

样例数据

input

4 50 18
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43

output

25

数据规模与约定

时间限制:1s

空间限制:256MB

注释

[ 一种最优的安排是用板拦住牛棚3-8,14-21,25-31,40-43.] 

这道题卡了三天还是一点思路都没有;

于是鼓起胆子去问章晟大佬;

得到这样的思路:

假设你把所有牛棚用一块板子盖起来要用多少长的木板?(以样例数据为例)

43-3+1=41对吧(因为是闭区间,两边都要盖起来,所以+1);

然后你再把两个相邻数据之间的距离算出来,排个序;

用个循环把大的间隔剪掉;

这就是剩下的最小的木板长度;

不得不说;

思路是真的奇特;

不再荀彧同学这种文科生的理解范围之内;

上代码:

#include
using namespace std;
int main()
{
	int m,s,c,sum=0;
	int a[222],b[111];
	cin>>m>>s>>c;
    for(int i=1;i<=c;i++)
        cin>>a[i];
    sort(a+1,a+c+1);
    sum=a[c]-a[1]+1;
    if(m>=c)
    {
    	cout<<c<<endl;
    	return 0;
    }
    for(int i=2;i<=c;i++)
        b[i-1]=a[i]-a[i-1]-1;
    sort(b+1,b+c);
    for(int i=c-1;i>c-m;i--)
        sum-=b[i];
    cout<<sum<<endl;
    return 0;
} 

从此发现,贪心是一个要用非正常人思路去理解的;

内心绝望;

心情简单;

end...

2>巧克力

上题目:

题目描述

有一块n××m的矩形巧克力,准备将它切成n××m块。巧克力上共有n-1条横线和m-1条竖线,你每次可以沿着其中的一条横线或竖线将巧克力切开,无论切割的长短,沿着每条横线切一次的代价依次为y1,y2,…,yn-1,而沿竖线切割的代价依次为x1,x2,…,xm-1。例如,对于下图6××4的巧克力,

我们先沿着三条横线切割,需要3刀,得到4条巧克力,然后再将这4条巧克力沿竖线切割,每条都需要5刀,则最终所花费的代价为y1+y2+y3+4*(x1+x2+x3+x4+x5)。 当然,上述简单切法不见得是最优切法,那么怎样切割该块巧克力,花费的代价最少呢?

输入格式

第一行为两个整数n和m。 接下来n-1行,每行一个整数,分别代表x1,x2,…,xn-1。 接下来m-1行,每行一个整数,分别代表y1,y2,…,ym-1。

输出格式

输出一整数,为切割巧克力的最小代价。

样例数据

input

6 4
2
1
3
1
4
4
1
2

output

42

数据规模与约定

时间限制:1s1s

空间限制:256MB256MB

注释

30%的数据,n<=100,m<=100 100%的数据,n<=10000,m<=10000

一刀一刀切下去的都是代价啊;

不能直接咬么;

这是一道很水得体;

正常人都能想得到;

要从代价大的开始切;

所以给两个数组排个序;

先切代价大的嘛;

然后再定义横着的块数和竖着的块数(定义时都是等于1,因为本来就有一块在那里嘛);

这个很简单,开个循环就好了;

直接放代码:

#include
using namespace std;
int n,m,sum=0;
int a[10100],b[10100];
int k1=1,k2=1;
inline bool cmp(int a,int b)
{
	return a>b;
}
void init()
{
	cin>>n>>m;
    for(int i=1;i<=n-1;i++)
        cin>>a[i];
    for(int i=1;i<=m-1;i++)
        cin>>b[i];
}
void work()
{
	sort(a+1,a+n,cmp);
	sort(b+1,b+m,cmp);
	for(int i=1;i<=m+n-2;i++)
		if(a[k1]>b[k2])
		    sum+=a[k1]*k2,k1++;
		else sum+=b[k2]*k1,k2++;
	cout<<sum<<endl;
}
int main()
{
	init();
	work();
	return 0;
} 

当时敲代码的时候脑子不清楚;

k1和k2的顺序neng反了;

所以说还是要仔细啊;

end...

先放着这两道题吧;

贪心估计还可以做两天;

下次争取做个更有水平的总结;

全文终。

你可能感兴趣的:({2018.5.8}荀(gou)彧(huo)的贪心初步小结)