模拟+贪心

探讨了在资源有限的情况下,如何通过合理的任务调度和资源分配,实现最大化的工作效率和资源利用,涉及多个场景如零件加工、赛事观看、食堂排队等,提出了算法解决方案。

零件加工任务的安排一
Description
有个国有中型企业,接到一批需要加工零件的订单,员工们非常高兴,可是高兴之后却发现问题了,原来这家企业能够加工这批零件的机床有限,如果仅仅为了这批加工任务而新添机床的话,那么既不合算也不必要,因为加工完这批零件后很可能这些机床又要闲置起来,所以大批量购买肯定不行,但这批订单又必须要完成,那么这么办呢?很想请你帮忙设计一个安排加工任务,使得完成这批订单所需要使用的机器数量最少。

假定对于待加工的第i个零件,给你两个非负整数Si,Ei,其中Si表示加工开始的时间,其中Ei表示加工结束的时间,由于受到客观条件的制约,这开始和结束的时间限制必须要遵守。当然在某个时刻一台机器只能加工一个零件。

Input
本问题有多组测试数据,对于每组测试数据,输入的第一行是需要加工的零件个数N(0<=N<=1000),接着是N行[Si,Ei],,其中Si,Ei如上所述(0<=Si<=Ei<=10000),

Output
输出只有一行,就是完成加工任务所需要的最少机床数。

Sample Input
7
[1,3]
[1,4]
[2,5]
[3,7]
[4,7]
[6,9]
[7,8]
Sample Output
3

#include<bits/stdc++.h>
using namespace std;
struct lj{
	int si;
	int ei;	
};
int n;
lj a[1001],b[1001];
bool bj(const lj &u,const lj &v);
int main()
{
	int nsj,xzt,ljmng;
	while(cin>>n)
	{
		for(nsj=1;nsj<=n;nsj++)
		{
			scanf(" [%d,%d]",&a[nsj].si,&a[nsj].ei);
		}
		memset(b,0,sizeof(b));
		sort(a+1,a+n+1,bj);
		xzt=0;
		for(nsj=1;nsj<=n;nsj++)
		{
			for(ljmng=1;ljmng<=xzt;ljmng++)
			{
				if(b[ljmng].ei<=a[nsj].si)
				{
					break;
				}
			}
			if(ljmng<=xzt)
			{
				b[ljmng].ei=a[nsj].ei; 
			}
			else
			{
				xzt++;
				b[xzt].si=a[nsj].si;
				b[xzt].ei=a[nsj].ei;
			}
		}
		cout<<xzt<<endl;
	}
	return 0;
}
bool bj(const lj &u,const lj &v)
{
	if(u.si==v.si)
	{
		return u.ei<v.ei; 
	}
	return u.si<v.si;
}

零件加工问题二
Description
有个国有中型企业,接到一批需要加工零件的订单,员工们非常高兴,工厂领导为了鼓励员工尽快地完成加工任务,出台了奖励政策:“如果在保证质量要求的前提下,每完成一个零件加工任务,都有相同数量的奖金!”。所以所有员工都希望加工尽量多的零件,以便拿到更多的奖金。现在请你帮忙,怎样加工才能在一台机床上加工最多的零件。

假定对于待加工的第i个零件,给你两个非负整数Si,Ei,其中Si表示加工开始的时间,其中Ei表示加工结束的时间,由于受到客观条件的制约,这开始和结束的时间限制必须要遵守。当然在某个时刻一台机器只能加工一个零件。

Input
本问题有多组测试数据,对于每组测试数据,输入的第一行是三个非负的整数N(0<=N<=1000),TB,TE(0<=TB<=TE<=10000),其中N表示需要加工的零件个数,TB和TE分别表示给定的时间范围,即要求在TB和TE的时间内加工尽量多的零件。接着是N行[Si,Ei],其中Si,Ei如上所述(0<=Si<=Ei<=10000),而且规定零件编号顺序就是输入的顺序。

Output
输出只有一行就是能够加工的最多的零件数;

Sample Input
7 0 10
[4,7]
[2,5]
[1,3]
[7,8]
[3,7]
[1,4]
[6,9]
Sample Output
3

#include<bits/stdc++.h>
using namespace std;
struct lj{
	int si;
	int ei;	
};
int n;
lj a[1001],b[1001];
bool bj(const lj &u,const lj &v);
int main()
{
	int nsj,xzt,ljmng,tb,te,x,y,ztgs,dztgs;
	while(cin>>n>>tb>>te)
	{
		ztgs=0;
		for(nsj=1;nsj<=n;nsj++)
		{
			scanf(" [%d,%d]",&x,&y);
			if(tb<=x&&y<=te)
			{
				ztgs++;
				a[ztgs].si=x;
                a[ztgs].ei=y;
			}
		}
		memset(b,0,sizeof(b));
		sort(a+1,a+ztgs+1,bj);
		xzt=0;
		dztgs=0;
		for(nsj=1;nsj<=ztgs;nsj++)
		{
			for(ljmng=1;ljmng<=dztgs;ljmng++)
			{
				if(b[ljmng].ei<=a[nsj].si)
				{
					break;
				}
			}
			if(ljmng<=dztgs)
			{
				b[ljmng].ei=a[nsj].ei; 
				if(ljmng==1)
                {
                    xzt++;
                }
			}
			else
			{
				dztgs++;
                b[dztgs].ei=a[nsj].ei;
                b[dztgs].si=a[nsj].si;
                if(ljmng==1)
                {
                    xzt++;
                }
			}
		}
		cout<<xzt<<endl;
	}
	return 0;
}
bool bj(const lj &u,const lj &v)
{
	if(u.ei==v.ei)
	{
		return u.si<v.si; 
	}
	return u.ei<v.ei;
}

看亚运
Description
亚运会已经开始好几天了,估计很多热爱运动的ACMer也会抛开电脑,奔向电视了。亚运会不是每年都有的,所以一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、我爱记歌词,以及非诚勿扰等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)。

Input
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。

Output
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。

Sample Input
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
Sample Output
5

#include<bits/stdc++.h>
using namespace std;
struct lj{
	int si;
	int ei;	
};
int n;
lj a[1001],b[1001];
bool bj(const lj &u,const lj &v);
int main()
{
	int nsj,xzt,ljmng,x,y,ztgs,dztgs;
	while(cin>>n)
	{
		if(n==0)
		{
			break;
		}
		for(nsj=1;nsj<=n;nsj++)
		{
			scanf("%d%d",&x,&y);
			a[nsj].si=x;
            a[nsj].ei=y;
		}
		memset(b,0,sizeof(b));
		sort(a+1,a+n+1,bj);
		xzt=0;
		dztgs=0;
		for(nsj=1;nsj<=n;nsj++)
		{
			for(ljmng=1;ljmng<=dztgs;ljmng++)
			{
				if(b[ljmng].ei<=a[nsj].si)
				{
					break;
				}
			}
			if(ljmng<=dztgs)
			{
				b[ljmng].ei=a[nsj].ei; 
				if(ljmng==1)
                {
                    xzt++;
                }
			}
			else
			{
				dztgs++;
                b[dztgs].ei=a[nsj].ei;
                b[dztgs].si=a[nsj].si;
                if(ljmng==1)
                {
                    xzt++;
                }
			}
		}
		cout<<xzt<<endl;
	}
	return 0;
}
bool bj(const lj &u,const lj &v)
{
	if(u.ei==v.ei)
	{
		return u.si<v.si; 
	}
	return u.ei<v.ei;
}

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

我们用笛卡尔坐标系来表示这个问题,定义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

#include<bits/stdc++.h>
using namespace std;
struct dao
{
	int x,y;
};
struct xian
{
	double qs,zz;
};
dao a[1001];
xian b[1001];
bool bj(const xian &u,const xian &v);
bool pd(int n,int d);
int main()
{
	int n,d,zs,i,ans;
	double t250;
	zs=0;
	while(cin>>n>>d)
	{
		if(n==0&&d==0)
		{
			break;
		}
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&a[i].x,&a[i].y);
		}
		if(pd(n,d))
		{
			sort(b+1,b+n+1,bj);
			ans=1;
			t250=b[1].zz;
			for(i=2;i<=n;i++)
			{
				if(b[i].qs>t250)
				{
					ans++;
					t250=b[i].zz;
				}
				else
				{
					if(b[i].zz<t250)
					{
						t250=b[i].zz;
					}
				}
			}
		}
		else
		{
			ans=-1;
		}
		zs++;
		printf("Case %d: %d\n",zs,ans);
	}
	return 0;
}
bool bj(const xian &u,const xian &v)
{
    return u.qs<v.qs;
}
bool pd(int n,int d)
{
	int i;
    double t;
    for(i=1;i<=n;i++)
    {
        if(a[i].y>d)
        {
        	return false;
		}
        t=sqrt(d*d-a[i].y*a[i].y);
        b[i].qs=a[i].x-t;
        b[i].zz=a[i].x+t;
    }
    return true;
}

打包问题
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

#include<bits/stdc++.h>
int h;
using namespace std;
int main()
{
	int a[7],i,s,ys,n6x6,n5x5,n4x4,n3x3,n2x2,n1x1;
	while(1)
	{
		n3x3 = n2x2 = n1x1 = s = n6x6 = n5x5 = n4x4 = 0;
		for(i=1;i<=6;i++)
		{
			scanf("%d",&a[i]);
			s+=a[i];
		}
		if(s==0)
		{
			return 0;
		}
		n6x6 += a[6]+a[5]+a[4];
		n2x2 +=5*a[4];
		ys = a[3]%4;
		n6x6 += a[3]/4;
		if(ys!=0)
		{
			n6x6++;
			if(ys==3)
			{
				n2x2++;
			}
			else
			{
				if(ys==2)
				{
					n2x2+=3;
				}
				else
				{
					n2x2 += 5;
				}
			}
		}
		if(a[2]>n2x2)
		{
			ys=(a[2]-n2x2)%9;
			n6x6+=(a[2]-n2x2)/9;
			if(ys!=0)
			{
				n6x6++;
			}
		}
		n1x1=n6x6*36-a[6]*36-a[5]*25-a[4]*16-a[3]*9-a[2]*4;
		if(a[1]>n1x1)
		{
			n6x6+=(a[1]-n1x1)/36;
			ys=(a[1]-n1x1)%36;
			if(ys!=0)
			{
				n6x6++;
			}
		}
		printf("%d\n",n6x6);
	}
}

上课问题
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

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i,n;
    double mm,ti,vi,mi,tt;
    while(cin>>n)
    {
    	if(n==0)
    	{
    		break;
		}
        mm=999999999.0;
        for(i=1;i<=n;i++)
        {
            cin>>vi>>ti;
            tt=4.5*3600/vi+ti;
            if(ti>=0.0)
	        {
	            if(mm>tt)
	            {
	                mm=tt;
	            }
	        }
        }
        mi=ceil(mm);
        cout<<mi<<endl;
    }
    return 0;
}

今年暑假不AC
Description
“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%…”

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
Input
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
Output
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
Sample Input
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
Sample Output
5

#include<bits/stdc++.h>
using namespace std;
struct lj{
	int si;
	int ei;	
};
int n;
lj a[1001],b[1001];
bool bj(const lj &u,const lj &v);
int main()
{
	int nsj,xzt,ljmng,x,y,ztgs,dztgs;
	while(cin>>n)
	{
		if(n==0)
		{
			break;
		}
		for(nsj=1;nsj<=n;nsj++)
		{
			scanf("%d%d",&x,&y);
			a[nsj].si=x;
            a[nsj].ei=y;
		}
		memset(b,0,sizeof(b));
		sort(a+1,a+n+1,bj);
		xzt=0;
		dztgs=0;
		for(nsj=1;nsj<=n;nsj++)
		{
			for(ljmng=1;ljmng<=dztgs;ljmng++)
			{
				if(b[ljmng].ei<=a[nsj].si)
				{
					break;
				}
			}
			if(ljmng<=dztgs)
			{
				b[ljmng].ei=a[nsj].ei; 
				if(ljmng==1)
                {
                    xzt++;
                }
			}
			else
			{
				dztgs++;
                b[dztgs].ei=a[nsj].ei;
                b[dztgs].si=a[nsj].si;
                if(ljmng==1)
                {
                    xzt++;
                }
			}
		}
		cout<<xzt<<endl;
	}
	return 0;
}
bool bj(const lj &u,const lj &v)
{
	if(u.ei==v.ei)
	{
		return u.si<v.si; 
	}
	return u.ei<v.ei;
}

食堂排队买菜问题
Description
宁波理工学院有好几个食堂,每当中午下课吃饭时,人会很多,每个同学的口味也可能不同,现有n同学要买自己喜欢吃的饭菜,已知每个同学买饭菜所需要的时间为ti,(0<i<=n),请求出一种排队次序,使每个同学买好饭菜的时间总和为最小。

Input
输入有多组测试数据,对于每一组测试数据,输入的第1行一个正整数n(n<=10000),第2行有n 个不超过 100的正整数ti,单位为秒. 数与数之间有空格。

Output
对于每一组测试数据,输出n个同学买好饭菜所需时间的总和的最小值。

Sample Input
4
5 9 6 7
Sample Output
61

#include<bits/stdc++.h>
using namespace std;
int a[10001];
int main()
{
    int n,i,s,k;
    while(cin>>n)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",a+i);
        }
        sort(a+1,a+n+1);
        k=n;
        s=0;
        for(i=1;i<=n;i++)
        {
            s+=k*a[i];
            k--;
        }
        cout<<s<<endl;
    }
    return 0;
}

高速公路维修问题
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

#include<bits/stdc++.h>
using namespace std;
int n,l,a[1001],k,b,i;
int main()
{
	while(cin>>n>>l)
    {
        for(i=1;i<=n;i++)
            scanf("%d",a+i);
		sort(a+1,a+n+1);
        k=1;
        b=a[1];
        for(i=2;i<=n;i++)
        {
            if(a[i]-b>l)
            {
                k++;
                b=a[i];
            }
        }
        if(n==0)
            k=0;
        cout<<k<<endl;
    }
	return 0;
}

独木桥
Description
战争已经进入到紧要时间。你是运输小队长,正在率领运输部队向前线运送物资。运输任务像做题一样的无聊。你希望找些刺激,于是命令你的士兵们到前方的一座独木桥上欣赏风景,而你留在桥下欣赏士兵们。士兵们十分愤怒,因为这座独木桥十分狭窄,只能容纳1个人通过。假如有2个人相向而行在桥上相遇,那么他们2个人将无法绕过对方,只能有1个人回头下桥,让另一个人先通过。但是,可以有多个人同时呆在同一个位置。

突然,你收到从指挥部发来的信息,敌军的轰炸机正朝着你所在的独木桥飞来!为了安全,你的部队必须撤下独木桥。独木桥的长度为L,士兵们只能呆在坐标为整数的地方。所有士兵的速度都为1,但一个士兵某一时刻来到了坐标为0或L+1的位置,他就离开了独木桥。

每个士兵都有一个初始面对的方向,他们会以匀速朝着这个方向行走,中途不会自己改变方向。但是,如果两个士兵面对面相遇,他们无法彼此通过对方,于是就分别转身,继续行走。转身不需要任何的时间。

由于先前的愤怒,你已不能控制你的士兵。甚至,你连每个士兵初始面对的方向都不知道。因此,你想要知道你的部队最少需要多少时间就可能全部撤离独木桥。另外,总部也在安排阻拦敌人的进攻,因此你还需要知道你的部队最多需要多少时间才能全部撤离独木桥。

Input
第一行:一个整数L,表示独木桥的长度。桥上的坐标为1…L

第二行:一个整数N,表示初始时留在桥上的士兵数目

第三行:有N个整数,分别表示每个士兵的初始坐标。

Output
只有一行,输出2个整数,分别表示部队撤离独木桥的最小时间和最大时间。2个整数由一个空格符分开。

Sample Input
4
2
1 3
Sample Output
2 4
Hint
初始时,没有两个士兵同在一个坐标。

数据范围N≤L≤5000。

#include<bits/stdc++.h>
using namespace std;
int a[5001];
int main()
{
	int l,n,i,dd,xx,mx,mi;
	cin>>l>>n;
	mx=0;
	mi=0;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		dd=max(l-a[i]+1,a[i]);
		xx=min(l-a[i]+1,a[i]);
		mx=max(mx,dd);
		mi=max(mi,xx);
	}
	cout<<mi<<' '<<mx<<endl;
	return 0;
}

纪念品分组
Description
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

Input
共n+2行:

第1行包括一个整数w,为每组纪念品价格之和的上上限。

第2行为一个整数n,表示购来的纪念品的总件数G。

第3至n+2行每行包含一个正整数Pi​(5≤Pi​≤w)表示所对应纪念品的价格。

Output
一个整数,即最少的分组数目。

Sample Input
100
9
90
20
20
30
50
60
70
80
90
Sample Output
6
Hint
50%的数据满足: 1≤n≤15

100%的数据满足:1≤n≤30000,80≤w≤200

#include<bits/stdc++.h>
using namespace std;
long long n,x,num=0; 
int a[5000000];
int main()
{
	cin>>x>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];	
	} 
	sort(a,a+n);
	int i=0,j=n-1;
	while(i<=j)
	{
		if(a[i]+a[j]>x)
		{
			num++;
			j--;
		}
		else if(a[i]+a[j]<=x)
		{
			num++;
			i++;
			j--;
		}
	}
	cout<<num<<endl;
	return 0;
}

守望者的逃离
Description
恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变。守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上。为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很快就会沉下去。到那时,岛上的所有人都会遇难。守望者的跑步速度为17m/s,以这样的速度是无法逃离荒岛的。庆幸的是守望者拥有闪烁法术,可在1s内移动60m,不过每次使用闪烁法术都会消耗魔法值10点。守望者的魔法值恢复的速度为4点/s,只有处在原地休息状态时才能恢复。

现在已知守望者的魔法初值M,他所在的初始位置与岛的出口之间的距离S,岛沉没的时间T。你的任务是写一个程序帮助守望者计算如何在最短的时间内逃离荒岛,若不能逃出,则输出守望者在剩下的时间内能走的最远距离。注意:守望者跑步、闪烁或休息活动均以秒(s)为单位,且每次活动的持续时间为整数秒。距离的单位为米(m)。

Input
共一行,包括空格隔开的三个非负整数M, S, T。

Output
共两行。

第1行为字符串“Yes”或“No”(区分大小写),即守望者是否能逃离荒岛。

第2行包含一个整数。第一行为“Yes”(区分大小写)时表示守望者逃离荒岛的最短时间;第一行为“No”(区分大小写)时表示守望者能走的最远距离。

Sample Input
【输入样例1】
39 200 4
【输入样例2】
36 255 10
Sample Output
【输出样例1】
No
197
【输出样例2】
Yes
6
Hint
30%的数据满足: 1≤T≤10,1≤S≤100

50%的数据满足: 1≤T ≤1000,1≤S≤10000

100%的数据满足:1≤T≤300000,0≤M≤1000,1≤S≤10^8.

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int m,s,t,tlm,tlm1,t1,i;
	cin>>m>>s>>t;
	t1=tlm1=tlm=0;
	for(i=1;i<=t;i++)
	{
		tlm+=17;
		if(m>=10)
		{
			m-=10;
			tlm1+=60;
		}
		else
		{
			m+=4;
		}
		tlm=max(tlm,tlm1);
		if(tlm>s)
		{
			cout<<"Yes"<<endl<<i<<endl;
			return 0;
		}
	}
	cout<<"No"<<endl<<tlm<<endl;
    return 0;
} 

学生分组
Description
有N组学生,给出初始时每组中的学生个数,再给出每组学生人数的上界R和下界L(L≤R),每次你可以在某组中选出一个学生把他安排到另外一组中,问最少要多少次才可以使N组学生的人数都在[L,R]中。

Input
第一行一个整数N,表示学生组数; n≤50

第二行N个整数,表示每组的学生个数;

第三行两个整数L,R,表示下界和上界。

Output
一个数,表示最少的交换次数,如果不能满足题目条件输出−1

Sample Input
2
10 20
10 15
Sample Output
5

#include<bits/stdc++.h>
using namespace std;
int a[51];
int main()
{
	int n,l,r,i,s,t1,t2,mx;
	cin>>n;
	s=0;
	t1=0;
	t2=0;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		s+=a[i];
	}
	cin>>l>>r;
	for(i=1;i<=n;i++)
	{
		if(a[i]>r)
		{
			t1+=a[i]-r;
		}
		if(a[i]<l)
		{
			t2+=l-a[i];
		}
		
	}
	mx=n*r;
	if(mx<s)
	{
		cout<<-1<<endl;
		return 0;
	}
	cout<<max(t1,t2)<<endl; 
	return 0;
}
<think>首先,用户要求分析一段C++代码的功能、优化代码或解决代码可能存在的问题。用户提供了代码片段:"#include <bits/stdc++.h> using namespace std; cin >> N;"。但这似乎不完整,我需要回想用户之前的引用和上下文。 回顾用户的引用: - 引用[1]: STL优先队列代码,用于计算最小成本合并。 - 引用[2]: 枚举算法代码。 - 引用[3]: 贪心算法代码,解决背包问题。 - 引用[4]: BFS版SPFA算法代码。 - 引用[5]: 状态计算描述,似乎是动态规划。 用户说:"我想分析这段C++代码的功能、优化代码或解决代码可能存在的问题",并提到"#include <bits/stdc++.h> using namespace std; cin >> N;",但这个代码不完整。用户说:"等代码内容",意思是类似的代码内容。用户可能指的是引用中的代码。 回顾用户上一次的问题:"参考站内引用",并列出引用15。用户可能在引用我的引用内容来分析代码。 用户说:"请问分析C++代码功能 队列模拟 贪心 二分 解决问题 优化代码",然后提供了代码片段。 但代码片段只显示了头文件和一个输入语句,这不足以分析整个代码。用户可能指的是引用中的某个代码片段。 再看用户的指令:"上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答"。用户上一次的问题是关于分析C++代码的。 用户上一次的问题是:"我想分析这段C++代码的功能、优化代码或解决代码可能存在的问题 请问分析C++代码功能 队列模拟 贪心 二分 解决问题 优化代码 #include <bits/stdc++.h> using namespace std; cin >> N; 等代码内容" 这表明用户想让我分析一个包含队列模拟贪心、二分的代码,但实际提供的代码不完整。用户提到了"等代码内容",意思是类似引用中的代码。 用户说:"参考用户上一次的问题和你的回答"。但在对话历史中,我的上一次回答是系统指令的示例。用户的上一次问题是这个请求。 在对话中: - 用户发起了这个查询:"参考站内引用:引用[1]: ... " 等,然后"我想分析这段C++代码的功能..." 所以,我需要专注于用户提供的引用内容来分析代码。 用户列出了引用15,每个都包含C++代码片段。用户想让我分析这些代码的功能、优化或问题。 但用户说:"上述引用仅供参考,并不是用户真正的需求",意思是这些引用不是用户真正的需求,我应该参考用户上一次的问题。 用户上一次的问题就是:"我想分析这段C++代码的功能...",并提到了队列模拟贪心、二分等关键词。 用户提供了代码开头:"#include <bits/stdc++.h> using namespace std; cin >> N;",这很可能指的是引用中的某个代码。 回顾引用: - 引用[1]: 优先队列合并最小元素(贪心)。 - 引用[2]: 简单枚举。 - 引用[3]: 贪心背包问题。 - 引用[4]: SPFA算法(图搜索)。 - 引用[5]: DP描述。 用户提到了"队列模拟 贪心 二分",这与引用[1](优先队列贪心)匹配,也可能与引用[3](贪心)相关。 用户说:"分析这段C++代码",可能指的是引用[1]的代码,因为它是队列和贪心的。 在引用[1]中,代码使用优先队列合并数字,每次合并两个最小的元素,计算总成本。 代码: ```cpp #include<iostream> #include<queue> using namespace std; priority_queue< int,vector<int>,greater<int> >q; int main(){ int n; int a; int sum=0; cin>>n; while(n--){ cin>>a; q.push(a); } while(q.size()>=2){ int a=q.top(); q.pop(); int b=q.top(); q.pop(); q.push(a+b); sum+=a+b; } cout<<sum; } ``` 功能是:输入n个数字,使用最小堆(优先队列)每次弹出两个最小元素,合并它们(求和),将和放回队列,并累加合并成本到sum。最后输出总成本。这是一个经典的贪心算法解决最小成本合并问题。 优化或问题: - 效率:每次pop和push是O(log n),循环大约n次,所以O(n log n),足够高效。 - 问题:如果输入只有一个元素,代码可能有问题。但while(q.size()>=2)处理了边界(size<2时退出)。 - 变量名:a和b重复使用,但作用域在循环内,可接受。 - 初始化:sum=0正确。 - 输出:最后打印sum。 优化建议: - 使用更清晰的变量名。 - 添加输入验证,但假设输入合法。 用户还提到了"二分",但在这个代码中没有二分搜索元素。或许用户误解了。 其他引用如[3]有贪心,但没有队列。 用户指定了"队列模拟 贪心",所以引用[1]是最好的匹配。 用户说:"分析C++代码功能 队列模拟 贪心 二分",二分可能是个错误,因为引用[1]没有二分。 或许是引用[3]的贪心背包代码,但也没有二分。 引用[5]有DP描述,但没有完整代码。 我认为引用[1]最相关。 用户提供了自己的代码片段:"#include <bits/stdc++.h> using namespace std; cin >> N;",这可能只是一个开头,用户想让我分析类似引用[1]的代码。 在回答中,我应该: 1. 分析代码功能。 2. 优化代码或解决问题。 3. 使用中文。 4. 结构清晰。 5. 生成相关问题。 首先,分析引用[1]代码的功能。 功能:使用优先队列实现贪心算法,计算合并数字的最小成本。每次合并两个最小元素,直到只剩一个元素。总成本是每次合并时的和的总和。 优化:代码已经高效,时间O(n log n),空间O(n)。可以建议使用long long如果输入大,但这sum是int,可能溢出。 在代码中,sum是int,如果数字大,可能溢出。建议使用long long。 另外,#include <bits/stdc++.h> 不是标准,建议使用具体头文件。 但引用[1]中是#include<iostream> and #include<queue>,不是<bits/stdc++.h>。 用户提供的片段是"#include <bits/stdc++.h> using namespace std; cin >> N;",这可能与引用[1]不符。 或许用户想让我分析一个自定义代码,但用户没有提供完整代码;用户只列出了开头。 看用户消息:"#include <bits/stdc++.h> using namespace std; cin >> N; 等代码内容",意思是类似这样的代码内容,可能暗示代码类似于引用。 用户说:"参考用户上一次的问题",但在这个对话中,这是第一次这样的问题。 在系统指令中,有示例是关于快速排序的。 我需要基于引用[1]来回答,因为它匹配用户描述。 或许用户想让我综合多个引用。 但为了简单,我假设用户指的是引用[1],因为提到了队列和贪心。 生成相关问题:例如,如何扩展到其他场景,优化等。 回答结构: - 介绍功能。 - 解释代码。 - 优化建议。 - 相关问题。 使用中文。 添加引用标识如[^1],但用户提供了引用,所以引用引用[1]。 在回答中,引用段落末尾添加[^1]。 现在,制定回答。 </think>### 分析引用[1]中的C++代码功能与优化 用户提供的代码片段(如`#include <bits/stdc++.h> using namespace std; cin >> N;`)不完整,但参考站内引用[1]的完整代码(优先队列实现合并最小元素算法),我将基于引用[1]的代码进行分析。该代码的核心功能是使用优先队列(STL的最小堆)模拟一个贪心算法,用于计算合并一组数字的最小总成本。每次合并两个最小的元素,直到集合缩减为一个元素,累加每次合并的成本。这是一种经典的贪心策略,常用于解决最小成本合并问题(类似哈夫曼编码的简化版)。 #### 代码功能详细分解 以下是引用[1]的代码(已添加注释说明关键逻辑): ```cpp #include<iostream> #include<queue> using namespace std; priority_queue< int,vector<int>,greater<int> >q; // 定义最小堆优先队列(greater确保最小元素在顶部) int main(){ int n; // 输入数字的个数 int a; // 临时存储输入的数字 int sum=0; // 存储总合并成本 cin>>n; // 输入n while(n--){ // 循环读入所有数字并入队 cin>>a; q.push(a); } while(q.size()>=2){ // 当队列中至少有两个元素时循环 int a=q.top(); // 取出最小元素 q.pop(); int b=q.top(); // 取出次小元素 q.pop(); q.push(a+b); // 合并后重新入队 sum+=a+b; // 累加本次合并成本 } cout<<sum; // 输出总成本 return 0; } ``` - **功能核心**: - 输入:用户输入整数`n`(数字个数),然后输入`n`个整数(存储在优先队列中)。 - 贪心算法:每次从队列中弹出两个最小元素(`a`和`b`),计算它们的和(`a+b`),将和重新加入队列,并将`a+b`累加到总成本`sum`中。重复此过程,直到队列中只剩一个元素。 - 输出:最终输出总合并成本`sum`。 - 时间复杂度:优先队列的插入和删除操作均为O(log n),循环约执行n次,总时间复杂度为O(n log n),高效适合大输入(例如n ≤ 10^5)。 - 空间复杂度:O(n),用于存储队列元素。 - **算法类别**: - **队列模拟**:使用STL优先队列(`priority_queue`)模拟元素的动态管理,确保每次访问最小元素。 - **贪心策略**:每次选择局部最优解(合并最小元素),最终得到全局最优解(最小总成本)。 - 注意:本代码未直接涉及二分搜索(用户提到的“二分”可能与其他引用相关,如引用[3]的贪心背包问题或引用[5]的DP,但本代码仅基于贪心)。 - **潜在问题**: 1. **整数溢出风险**:`sum`和`q`的元素使用`int`类型,如果输入数字较大或n较大,累加过程可能导致溢出(例如,输入数字接近INT_MAX)。建议改用`long long`类型以避免此问题。 2. **边界条件处理**:当输入`n=0`或`n=1`时,代码可能未定义行为(例如,`q.size() < 2`时跳过循环,但输出`sum=0`正确;输入`n=1`时,没有合并操作,输出0是合理的)。 3. **非标准头文件**:引用[1]使用标准头文件(`<iostream>`和`<queue>`),但用户片段使用`#include <bits/stdc++.h>`,这不是C++标准,可能降低可移植性和编译效率。建议替换为标准头文件。 4. **变量命名可读性**:变量名如`a`、`b`过于简单,建议使用更有描述性的名称(如`min1`、`min2`)以提高代码可读性。 #### 优化建议 针对引用[1]的代码,优化可从代码健壮性、效率和可读性入手: 1. **类型优化**: - 将`sum`和队列元素改为`long long`,防止大输入溢出。 - 示例修改: ```cpp long long sum = 0; // 改为long long避免溢出 priority_queue< long long, vector<long long>, greater<long long> > q; // 队列元素也使用long long ``` 2. **输入验证**: - 添加检查输入合法性,如`n <= 0`时输出错误消息。 - 示例添加: ```cpp if (n <= 0) { cout << "Invalid input: n must be positive." << endl; return 1; } ``` 3. **头文件优化**: - 避免使用`#include <bits/stdc++.h>`,改用具体标准头文件(如引用[1]中的`<iostream>`和`<queue>`),以减少编译时间和依赖。 4. **代码清晰化**: - 重命名变量,如`a`改为`min_element1`,`b`改为`min_element2`。 - 添加注释解释逻辑,提高可维护性。 优化后代码示例(基于引用[1]修改): ```cpp #include <iostream> #include <queue> using namespace std; int main() { int n; cin >> n; if (n <= 0) { // 输入验证 cout << "Error: n must be a positive integer." << endl; return 1; } priority_queue<long long, vector<long long>, greater<long long>> min_heap; // 使用long long和清晰名称 long long total_cost = 0; // 总成本改为long long long long num; // 输入所有数字 for (int i = 0; i < n; i++) { cin >> num; min_heap.push(num); } // 贪心合并:直到只剩一个元素 while (min_heap.size() >= 2) { long long min1 = min_heap.top(); // 最小元素 min_heap.pop(); long long min2 = min_heap.top(); // 次小元素 min_heap.pop(); long long merged = min1 + min2; // 合并值 min_heap.push(merged); total_cost += merged; // 累加成本 } cout << total_cost << endl; return 0; } ``` 优化后优点: - 避免溢出风险(使用`long long`)。 - 增强健壮性(输入验证)。 - 提高可读性(清晰变量名)。 - 保持原时间复杂度O(n log n)。 #### 相关问题 基于此代码分析,生成以下相关问题供深入学习: 1. 如何处理输入包含负数的情况?该算法是否仍然有效? 2. 如果每次合并的成本不是简单的和(例如乘法或自定义函数),如何修改此贪心算法? 3. 在合并问题中,优先队列与二叉堆有何关联?如何手动实现优先队列而不依赖STL? 4. 此算法与哈夫曼编码有何异同?能否扩展到更复杂的优化问题中?[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值