LOJ 一本通提高篇1.1貪心算法 例題

複習時食用,會比較簡略。


目錄

#10000. 「一本通 1.1 例 1」活動安排

#10001. 「一本通 1.1 例 2」種樹

#10002. 「一本通 1.1 例 3」噴水裝置

#10003. 「一本通 1.1 例 4」加工生產調度

#10004. 「一本通 1.1 例 5」智力大沖浪


#10000. 「一本通 1.1 例 1」活動安排

題目

題目大意

有n個活動,每個活動i都有起始時間s_i和結束時間f_i。

若區間[s_i,f_i)與區間[s_j,f_j)不相交,則活動i與活動j相容。

選擇出由互相兼容的活動組成的最大集合。

1<=n<=1000。

題目分析

貪心。

將每個活動的結束時間從小到大排序。

每次選擇結束時間最早的開始時間大於等於結束時間的活動。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct node{int s,f;}a[1010];
int cmp(node x,node y)
{
	if(x.f==y.f) return x.s<y.s;
	else return x.f<y.f;
}

int main()
{
	int n; scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].s,&a[i].f);
	sort(a+1,a+1+n,cmp);//按結束時間從小到大排序
	int ans=1,end=a[1].f-1;
	for(int i=2;i<=n;i++)
	{
		if(a[i].s>end) { ans++; end=a[i].f-1; }
	}
	printf("%d",ans);
	return 0;
}

 

#10001. 「一本通 1.1 例 2」種樹

題目

題目大意

某條街被劃爲n條路段,每個路段可以種一棵樹。

給出了h組建議,希望在路段b到e之間至少要種t棵樹。

問至少要種多少棵樹。

30%的數據滿足0<n<=1000,0<h<=500;

100%的數據滿足0<n<3*10^4,h<=5000,0<b<=e<=3*10^4,t<=e-b+1。

題目分析

貪心。

跟上一題有異曲同工之妙。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

bool b[30010];
struct node{int b,e,t;}a[5010];
int cmp(node x,node y) { return x.e<y.e; }

int main()
{
	int n,h; scanf("%d%d",&n,&h);
	memset(b,false,sizeof(b));
	for(int i=1;i<=h;i++)
	{
		scanf("%d%d%d",&a[i].b,&a[i].e,&a[i].t);
	}
	sort(a+1,a+1+h,cmp);//按種樹路段的末尾排序
	int ans=0;
	for(int i=1;i<=h;i++)
	{
		int s=0;//先找這一段路已有的樹
		for(int j=a[i].b;j<=a[i].e;j++) if(b[j]) s++;
		if(s<a[i].t)//還沒有種夠
		{
			for(int j=a[i].e;j>=a[i].b;j--)
			{
				if(b[j]==false)//這個位置沒有樹就種啊
				{
					s++; b[j]=true; ans++;
					if(s==a[i].t) break;
				}
			}
		}
	}
	printf("%d",ans);
	return 0;
}

 

#10002. 「一本通 1.1 例 3」噴水裝置

題目

題目大意

長L米,寬W米的草坪裏裝有n個澆灌噴頭。

每個噴頭都裝在草坪中心線上。

知道每個噴頭的位置,以及它能覆蓋到的澆灌範圍。

問同時澆灌整塊草坪最少需要打開多少個噴頭?

對於100%的數據,n<=15000。

題目分析

    .       .       “.”       .       .     

            .       “.”       .   

                    “.”   

            .       “.”       .        

    .       .       “.”       .       .       

下劃線的爲半徑,“引號”中的是草坪寬。

紅色的是能澆灌到的最邊上的草坪寬,用kk=sqrt(r*r-(w/2)*(w/2))表示。是美妙的勾股啊!!

則最左邊a[s].a=x-kk,最右邊a[s].b=x+kk。

如果澆灌的半徑*2<草坪寬就不考慮這個噴頭,不要問我爲什麼,或者你告訴我要它有何用。

剩下的水到渠成。

還不懂就看代碼吧。

代碼

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

struct node{double a,b;}a[15010];
int cmp(node x,node y) { return x.a<y.a; }

int main()
{
	int t; scanf("%d",&t);
	while(t--)
	{
		int n,l,w,s=0; scanf("%d%d%d",&n,&l,&w);
		for(int i=1;i<=n;i++)
		{
			int x,y; scanf("%d%d",&x,&y);
			if(y*2<w) continue; s++;
			double kk=sqrt(y*y*1.0-w*w/4.0);
			a[s].a=x*1.0-kk;//能澆灌到的最邊上的最左
			a[s].b=x*1.0+kk;//能澆灌到的最邊上的最右
		}
		sort(a+1,a+1+s,cmp);
		int d=1,ans=0;
		double ll=0;//目前能澆灌到的最邊上的草坪的長  
		bool k=true;
		while(ll<l)//革命尚未成功 
		{
			ans++; double maxx=ll;
			while(a[d].a<=maxx&&d<=s)
			{
				ll=max(ll,a[d].b); d++;
				//當然是找符合要求且半徑長的噴頭a 
			}
			if(maxx==ll) { printf("-1\n"); k=false; break; }
		}
		if(k) printf("%d\n",ans);
	}
	return 0;
}

 

#10003. 「一本通 1.1 例 4」加工生產調度

題目

題目大意

n個產品在A、B兩個車間加工,必須先在A車間加工後纔可以到B車間加工。

產品i在A,B兩車間加工的時間分別爲 A_i, B_i,安排這 n個產品的加工順序,使總的加工時間最短。

對於100%的數據,0<n<1000,所有數值皆爲整數。

題目分析

???沒有分析,很迷???

一本通上的證明並沒有看懂,我太辣雞了。

反正是這樣做的:

設Mi=min(ai,bi)。

將M從小到大排序,若Mi=ai,就將它放在從頭開始的作業後面。

反之放在從尾開始的作業前面。

順序排好了就直接做啊。

代碼

#include<cstdio>
#include<cstring>
#include<cstring>
#include<algorithm>
using namespace std;

int s[1010];
struct nod1{int a,b,m,h;}a[1010];
struct nod2{int a,b;}b[1010];
int cmp(nod1 x,nod1 y) { return x.m<y.m; }

int main()
{
	int n; scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].a);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].b);
		a[i].m=min(a[i].a,a[i].b); a[i].h=i;
		b[i].a=a[i].a; b[i].b=a[i].b;
	}
	sort(a+1,a+1+n,cmp);
	int st=1,ed=n;
	for(int i=1;i<=n;i++)
	{
		if(a[i].m==a[i].a) { s[st]=a[i].h; st++; }
		else { s[ed]=a[i].h; ed--; }
	}
	int ans=0,d=0;
	for(int i=1;i<=n;i++)
	{
		d+=b[s[i]].a;
		ans=max(d+b[s[i]].b,ans+b[s[i]].b);
	}
	printf("%d\n",ans);
	for(int i=1;i<=n;i++) printf("%d ",s[i]);
	return 0;
}

 

#10004. 「一本通 1.1 例 5」智力大沖浪

題目

題目大意

比賽分爲n個時段,每個遊戲都必須在t_i前完成,否則從獎勵費m元中扣去一部分錢 w_i。

每個遊戲能在一個時段內完成,問小偉能贏取最多的錢。 

對於100%的數據,有n<=500,1<=t_i<=n。

題目分析

肯定挑錢多的先做啊,需要爲什麼嗎???

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

bool f[250010];
struct node{int time,money;}a[510];
int cmp(node x,node y) { return x.money>y.money; }

int main()
{
	int m,n; scanf("%d%d",&m,&n);
	memset(f,false,sizeof(f));
	for(int i=1;i<=n;i++) scanf("%d",&a[i].time);
	for(int i=1;i<=n;i++) scanf("%d",&a[i].money);
	sort(a+1,a+1+n,cmp);//按錢的多少排序
	for(int i=1;i<=n;i++)
	{
		bool k=false;
		for(int j=a[i].time;j>=1;j--)
		{
			if(!f[j]) { f[j]=true; k=true; }
			if(k) break;
		}
		if(!k) m-=a[i].money;
	}
	printf("%d",m);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章