二分查找【洛谷P1094】

题目链接在这:https://www.luogu.org/problemnew/show/P1094

题目很简单,算法也很简单,我相信没有人不会做这个题的,但是我为什么要写这篇题解呢,因为我被一个东西坑了将近一个小时(我太蒻了!)。

看了好多题解都是用两个指针一个开头一个结尾然后移动,但是我确实一开始就不是这样想的啊!(我蒻!)

先说思路:sort是肯定要sort的,然后直接for一遍每一个物品,用vis数组记录每一件物品有没有被访问过,然后就二分查找w-wi,(问题来了!一开始用的是lower_bound,不知道当时怎么想的,可能是我以前lower_bound用的比较多吧,lower_bound是查找数组中第一个x的位置,这与题目解法肯定大相径庭了),二分查找就用STL的upper_bound,但是问题又来了,upper_bound返回的是位置的后一个位置,所以upper_bound(v.begion,v.end(),x)-v.begin-1才可以找到最后一个x的位置。         每次从w-wi的最后一个位置往前找,并将找到的用vis标记。   这个题目大概就这个一回事。

下面是代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 31000;
bool vis[maxn];
void init()
{
	memset(vis,0,sizeof(vis));
}
int main()
{
	int w;
	while(cin>>w)
	{
		init();
		vector<int> v;
		int n;
		cin>>n;
		for(int i=0;i<n;i++)
		{
			int tmp;
			cin>>tmp;
			v.push_back(tmp);
		}
		sort(v.begin(),v.end());
		int cnt = 0;
		for(int k=0;k<v.size();k++)
		{
			if(!vis[k])
			{
				vis[k] = 1;
				bool found = false;
				int t = w-v[k];
				int pos = upper_bound(v.begin(),v.end(),t)-v.begin()-1;
				if(pos==0)
				{
					cnt++;
					continue;
				}
				for(int i=pos;i>=k;i--)
				{
					if(!vis[i])
					{
						vis[i] = 1;
						cnt++;
						found = true;
						break;
					}
				}
				if(!found)
				{
					cnt++;
				}
			}
		}
		cout<<cnt<<endl;
	}
	return 0;
}

PS:今天水了一篇题解,真开心。

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/83107267
今日推荐