hihoCoder[Offer收割]编程练习赛2题目解析

题目1 : 买零食
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
小Ho很喜欢在课间去小卖部买零食。然而不幸的是,这个学期他又有在一教的课,而一教的小卖部姐姐以冷若冰霜著称。第一次去一教小卖部买零食的时候,小Ho由于不懂事买了好一大堆东西,被小卖部姐姐给了一个“冷若冰霜”的眼神,食欲都下降了很多。
从那以后,小Ho就学乖了,去小卖部买东西只敢同时买3包以内的零食,并且价格加起来必须是5的整数倍,方便小卖部姐姐算价格。
但是小Ho不擅长计算,所以他把小卖部里所有零食的价格以及他对这个零食的渴望度都告诉了你,希望你能够帮他计算出在不惹恼小卖部姐姐的前提下,能够买到零食的渴望度之和最高是多少?
输入
每个输入文件包含多组测试数据,在每个输入文件的第一行为一个整数Q,表示测试数据的组数。
每组测试数据的第一行为一个正整数N,表示小卖部中零食的数量。
接下来的N行,每行为一个正实数A和一个正整数B,表示这种零食的价格和小Ho对其的渴望度。
一种零食仅有一包。
对于100%的数据,满足1 <= Q <= 10,1<=N<=50,0<A<=10,1<=B<=100。
对于100%的数据,满足A的小数部分仅可能为0.5或0。
输出
对于每组测试数据,输出一个整数Ans,表示小Ho可以获得最大的渴望度之和。
样例输入
1
4
0.5 6
4.5 7
5.0 4
2.0 9
样例输出

17

使用最简单的枚举就可以解决该问题。在有些情况下,只买两包零食甚至一包零食可能要比买三包零食的情况更优,所以三种情况都要考虑。

AC代码:

#include<iostream>
using namespace std;
float price[100];
int wanted[100];
int main()
{
	int Q;
	scanf("%d",&Q);
	while(Q--)
	{
		int N;
		int ans=0;
		scanf("%d",&N);
		for(int i=0;i<N;i++)
		{
			cin>>price[i]>>wanted[i];
		}
		for(int i=0;i<N;i++)
		{
			for(int j=0;j<N;j++)
			{
				for(int k=0;k<N;k++)
				{
					if(i!=j&&j!=k&&i!=k)
					{
						int m=price[i]+price[j]+price[k];
						if((!(m%5))&&(!(price[i]+price[j]+price[k]-m)))
						{
							if(wanted[i]+wanted[j]+wanted[k]>ans)
								ans=wanted[i]+wanted[j]+wanted[k];
						}
					}
				}
			}
		}
		for(int i=0;i<N;i++)
		{
			for(int j=0;j<N;j++)
			{
				if(i!=j)
				{
					int m=price[i]+price[j];
					if((!(m%5))&&(!(price[i]+price[j]-m)))
					{
						if(wanted[i]+wanted[j]>ans)
							ans=wanted[i]+wanted[j];
					}
				}
			}
		}
		for(int i=0;i<N;i++)
		{
			int m=price[i];
			if((!(m%5))&&(!(price[i]-m)))
			{
				if(wanted[i]>ans)
					ans=wanted[i];
			}
		}
		printf("%d\n",ans);
	}
}
题目2 : 清理海报
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi实验室所在的建筑一楼有一个用于贴海报的黑板,不停的有新的海报往上贴,也会安排人员不断的对海报进行清理,而最近,轮到了小Hi去对海报进行清理。
黑板是一块W*H大小的区域,如果以左下角为直角坐标系的话,在上次清理后第i张贴上去的海报可以视作左下角为(X1i, Y1i),右上角为(X2i, Y2i)的一个矩形。
撕去一张海报会导致所有覆盖在其上的海报都被同时撕掉(这样被称为连带,这个过程是具有传递性的,即如果A覆盖B,B覆盖C,那么撕掉C会导致A和B均被撕掉),但是一张海报想要被手动撕掉的话需要至少存在一个角没有被其他海报覆盖(海报A被海报B覆盖当且仅当他们存在面积大于0的交集并且A在B之前贴出,海报A的一个角被海报B覆盖当且仅当这个顶点处于海报B的内部)。
于是现在问题来了,为了节约时间,小Hi决定一次性撕掉尽可能多的海报,那么他应该选择哪张海报呢?在效果相同的情况下,小Hi倾向于选择更早贴出的海报。
输入
每个输入文件仅包含单组测试数据。
每组测试数据的第一行为三个正整数W,H和N,分别表示黑板的宽、高以及目前张贴出的海报数量。
接下来的N行,每行为四个正整数X1i、Y1i、X2i和Y2i,描述第i张贴出的海报。
对于20%的数据,满足1<=N<=5,1<=W,H<=10
对于100%的数据,满足1<=N<=1000,0<=X1i, X2i <= W, 0<=Y1i, Y2i<=H, 1<=W,H<=108
输出
对于每组测试数据,输出两个正整数Ans和K,表示小Hi一次最多能撕掉多少张海报,和他选择的海报是第几张贴出的。
样例输入
6 7 4
0 0 4 4
1 0 3 4
1 4 4 6
0 0 3 5
样例输出
3 1
撕去一张海报会导致所有覆盖在其上的海报都被同时撕掉,想到了什么呢?对了,图!每张海报看成一个点,如果A海报撕去后B海报也会被撕去,那么就从A到B连一条边,然后搜索进行遍历。这里要判断海报的两种状态,一种是是否被覆盖;一种是是否至少存在一个角没有被覆盖。这里我写了5个checkin函数,前4个函数判断海报i的四个角是否被海报j覆盖,最后1个函数判断一种特殊的情况,即两张海报之间存在覆盖,但是任何一个海报的四个角都没有被覆盖,类似于十字架。

AC代码:

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int x1[1010],x2[1010],y1[1010],y2[1010];
int map[1010][1010];
int flag[1010],vis[1010];
int W,H,N,num;

bool checkin1(int i,int j)
{
	if((x1[j]<x2[i])&&(x2[i]<x2[j])&&(y1[j]<y2[i])&&(y2[i]<y2[j])) return 1;
	return 0;
}

bool checkin2(int i,int j)
{
	if((x1[j]<x2[i])&&(x2[i]<x2[j])&&(y1[j]<y1[i])&&(y1[i]<y2[j])) return 1;
	return 0;
}

bool checkin3(int i,int j)
{
	if((x1[j]<x1[i])&&(x1[i]<x2[j])&&(y1[j]<y1[i])&&(y1[i]<y2[j])) return 1;
	return 0;
}

bool checkin4(int i,int j)
{
	if((x1[j]<x1[i])&&(x1[i]<x2[j])&&(y1[j]<y2[i])&&(y2[i]<y2[j])) return 1;
	return 0;
}

bool checkin5(int i,int j)
{
	if((x1[i]>=x1[j])&&(x1[i]<=x2[j])&&(x2[i]>=x1[j])&&(x2[i]<=x2[j])
	&&(y1[j]>=y1[i])&&(y1[j]<=y2[i])&&(y2[j]>=y1[i])&&(y2[j]<=y2[i]))
	{
		return 1;
	}
	return 0;
} 

int find(int i)
{
	num=1;
	queue<int> q;  
	q.push(i);
	vis[i]=1;
	while(!q.empty())
	{
		int k=q.front();
		q.pop();
		for(int j=1;j<=N;j++)
		{
			if((map[k][j])&&(!vis[j])&&(k!=j)) 
			{
				vis[j]=1;
				num++;
				q.push(j);
			}
		}
	}
	return num;
}

int main()
{
	scanf("%d %d %d",&W,&H,&N);
	memset(map,0,sizeof(map));
	memset(flag,0,sizeof(flag));
	for(int i=1;i<=N;i++)
	{
		cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
	}
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<=N;j++)
		{
			if(j>i)
			{
				if(checkin1(j,i)||checkin2(j,i)||checkin3(j,i)
				||checkin4(j,i)||checkin1(i,j)||checkin2(i,j)
				||checkin3(i,j)||checkin4(i,j)||checkin5(i,j)||checkin5(j,i))
				{
					map[i][j]=1;
				}
			}
		}
	}
	int flag1,flag2,flag3,flag4;
	for(int i=1;i<=N;i++)
	{
		flag1=0,flag2=0,flag3=0,flag4=0;
		for(int j=1;j<=N;j++)
		{
			if(j>i)
			{
				if(checkin1(i,j)) flag1=1;
				if(checkin2(i,j)) flag2=1;
				if(checkin3(i,j)) flag3=1;
				if(checkin4(i,j)) flag4=1;
			}
		}
		if(flag1&&flag2&&flag3&&flag4)
		{
			flag[i]=1;
		}
	}
	int answer1=0,answer2=0;
	for(int i=1;i<=N;i++)
	{
		if(!flag[i])
		{
			memset(vis,0,sizeof(vis));
			int temp=find(i);
			if(answer1<temp)
			{
				answer1=temp;
				answer2=i;
			}
		}
	}
	printf("%d %d\n",answer1,answer2);
}
还有两道题本人当时没有做出来,以后再更新吧。


你可能感兴趣的:(hihoCoder[Offer收割]编程练习赛2题目解析)