ccf12-5祭坛(80分)

过几天要考ccf了,提前刷刷题。

链接 http://115.28.138.223/view.page?gpid=T43 

想了好久,只弄出80分的做法,100分的做法没有找到。

主要思路:

先考虑一个比较简单的情况:

给定一条横线上的点(a,b0),(a,b1)...(a,bn),以及一条竖线上的点(a0,b),(a1,b)...(an,b),求两条线能组成的最多结界数。

很容易找出做法:

1)找出两条线的交点(a,b)

2)从交点向外的四个方向(上下左右)上最少的点的数量就是最多结界数。

可以看出上面的想法是正确的。(一种构造方法是,将四个方向上离(a,b)最近的四个点连起来成为一个屏障,第二近的组成一个屏障,第三近的。。。)

这个可以通过二分查找确定出来。


知道了以上的简单情况,复杂的情况就好说了。。复杂的情况就是很多根竖线和很多根横线相交的问题。直观的想法就是,每根横线和每个竖线都测一下可以做多少结界。然后找出最大的并计数即可。但是这样有一点浪费时间,举个例子,如果我们得到的最大结界数是n,那么任何有少于2n-1的横线是没有必要再检查了(产生n个结界至少要有2n个点)。所以每当得到一个更大的结界数,我们就可以做一次更新,把那些不可能的线段剔除掉,这样可以节约一点时间。代码如下:


#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
struct point
{
	int x,y;
};
bool comparebyx(const point& a,const point& b)
{
	return a.x<b.x ||(a.x==b.x && a.y<b.y);
}
bool comparebyy(const point& a,const point& b)
{
	return a.y<b.y ||(a.y==b.y && a.x<b.x);
}
bool compare(const vector<point>& a,const std::vector<point> b)
{
	return a.size()>b.size();
}
int findX(const vector<point>& sameY,int x)
{
	if(x<=sameY[0].x)
		return 0;
	int l = 0,r = sameY.size();
	while(l<r-1)
	{
		int mid = (l+r)/2;
		if(sameY[mid].x==x)
		{
			return 0;
		}
		else
			if(sameY[mid].x<x)
				l = mid;
			else
				r = mid;
	}
	return min(l+1,int(sameY.size()-l-1));
}
int findY(const vector<point>& sameX,int y)
{
	if(y<=sameX[0].y)
		return 0;
	int l = 0,r = sameX.size();
	while(l<r-1)
	{
		int mid = (l+r)/2;
		if(sameX[mid].y==y)
		{
			return 0;
		}
		else
			if(sameX[mid].y<y)
				l = mid;
			else
				r = mid;
	}
	return min(l+1,int(sameX.size()-l-1));
}
int main()
{
	int  n,q,a,b;
	cin >> n>>q;
	vector<point> myVec(n);
	for(int i(0);i<n;i++)
	{
		scanf("%d %d",&(myVec[i].x),&(myVec[i].y));
	}
	vector<point> myVec0(myVec);
	sort(myVec.begin(),myVec.end(),comparebyx);
	sort(myVec0.begin(),myVec0.end(),comparebyy);
	vector<vector<point> >sameX(1);
	vector<vector<point> >sameY(1);
	int index = 0;
	sameX[index].push_back(myVec[0]);
	for(int i(1);i<myVec.size();i++)
	{
		if(myVec[i].x==myVec[i-1].x)
			sameX[index].push_back(myVec[i]);
		else
		{
			if(sameX[index].size()==1){
				sameX[index][0]=myVec[i];
			}
			else
			{
				sameX.push_back(vector<point>());
				index++;
				sameX[index].push_back(myVec[i]);
			}
		}
	}
	index = 0;
	sameY[index].push_back(myVec0[0]);
	for(int i(1);i<myVec0.size();i++)
	{
		if(myVec0[i].y==myVec0[i-1].y)
			sameY[index].push_back(myVec0[i]);
		else
		{
			if(sameY[index].size()==1){
				sameY[index][0]=myVec0[i];
			}
			else
			{
				sameY.push_back(vector<point>());
				index++;
				sameY[index].push_back(myVec0[i]);
			}
		}
	}
	bool f = 1;

	sort(sameX.begin(),sameX.end(),compare);
	sort(sameY.begin(),sameY.end(),compare);
	int maxnum = 0,count = 0;
	/*for(int i(0);i<sameX.size();i++){
		for(int j(0);j<sameX[i].size();j++)
			cout << sameX[i][j].x<<' ';
		cout <<endl;
	}*/
	for(int i(0);i<sameX.size();i++)
	{
		for(int j(0);j<sameY.size();j++)
		{
			int x =sameX[i][0].x;
			int y = sameY[j][0].y;
			int res = min(findX(sameY[j],x),findY(sameX[i],y));
			if(res>maxnum)
			{
				maxnum = res;
				count = 1;
				while(!sameX.empty() && sameX.back().size()<=2*maxnum-1)
					sameX.pop_back();
				while(!sameY.empty() && sameY.back().size()<=2*maxnum-1)
					sameY.pop_back();
			}
			else
				if(res == maxnum)
					count++;
		}
	}
	if(q==1)
		cout << maxnum<<endl;
	else
		cout << count<<endl;
	return 0;
}
/*
26 2
0 5
1 1
1 5
1 9
3 5
3 10
4 0
4 1
4 2
4 4
4 6
4 9
4 11
5 0
5 2
5 4
5 8
5 9
5 10
5 11
6 5
7 5
8 5
9 10
10 2
10 5
*/
除了上面的想法,感觉还可以优化,优化的方面就是更新的时候其实可以剔除掉更多:对于剩下的横线,如果没有比自身纵坐标更大/更小的点,那么该横线就可以剔除掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值