【hdoj_1051】WoodenSticks

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1051

题意可以理解为:给定若干个二元数对,要将这些数对分为不同的组,同一组中的若干个二元数对可以排列成一个顺序,这个顺序使得二元数对按照两个指标中的任意一个指标都是(不严格)递增的,待求的是,在这种分组方式下,最少可以分多少组.

思路:可以先按照两个指标中的一个指标(长度)给这些二元数对排序,再依次序,根据另一个指标(重量)确定第一组最多可以有多少个二元数对,将这些作为一组,然后以同样的方式考虑剩余的数对.


例如给定(4,9), (5,2), (2,1), (3,5) 和 (1,4).

首先,按照第一个指标排序之后为(1,4),(2,1),(3,5),(4,9)(5,2).记为A,B,C,D,E.

然后,对比第二个指标,A之后的B的第二个指标为B2=1<4=A2不满足.C2=5>4=A2满足,所以C可以与A一组.D2=9>5=C2,所以D可以与A和C一组.E2=2<D2=9,所以E和A不能为一组.第一轮结束,得到A,C和D可以为一组,剩余B和E.

接着,考虑剩余的B和E,E2=2>B2=1,所以E和B可以为一组,没有剩余的了.

所以,这样可以分为两组.



C++代码如下

#include<iostream>
#include<algorithm>
using namespace std;

//木棍 结构体 
struct WoodenStick
{
	int Length;
	int Weight;
	
	//构造函数 
	WoodenStick(int l=0,int w=0)
	{
		Length = l;
		Weight = w;
	}
	//设置函数 
	void Set(int l=0,int w=0)
	{
		Length = l;
		Weight = w;
	}
	//< 运算符重载,在排序的时候用到 
	bool operator < (WoodenStick ws)
	{
		if(Length<ws.Length)
			return true;
		if(Length == ws.Length)
		{
			if(Weight<=ws.Weight)
				return true;
			else return false;
		}
		else return false;
	}
};

//折半插入排序 
void BinSort(WoodenStick ws[],int n)
{
	for(int i=0;i<n;i++)
	{
		int low = 0,high = i-1,mid;
		while(low<=high)
		{
			mid = (low+high) / 2;
			if(ws[i]<ws[mid])	
				high = mid - 1;
			else
				low = mid + 1;
		}
		WoodenStick temp = ws[i];
		for(int j=i;j>low;j--)
			ws[j] = ws[j-1];
		ws[low] = temp;
	}
}

int main()
{
	int T;
	cin >> T;//输入测试数据的组数 
	while(T--)
	{
		int n,Length,Weight;//分别为木棍数目 木棍长度 木棍重量 
		cin >> n;
		WoodenStick *ws = new WoodenStick[n];  //木棍结构体数组 
		for(int i=0;i<n;i++)
		{
			cin >> Length >> Weight;
			ws[i].Set(Length,Weight); //将数据存入木棍结构体数组 
		}
		BinSort(ws,n);//从小到大排序 
		
		//调试用  查看排序的结果是否正确 
		/* 
		for(int i=0;i<n;i++)
			cout << ws[i].Length << " " << ws[i].Weight << endl;
		*/
		
		int result = 0;//每一组测试数据的结果
		int * IsOk = new int[n];//是否已经分组分配完毕,即是否可以不再考虑这个二元数对了. 
		for(int i=0;i<n;i++) IsOk[i] = 0;//开始都为0,表示所有的二元数对都没有分配完毕 
		
		for(int i=0;i<n;i++)
		{
			if(!IsOk[i])//针对某个还没有分配的数对 
			{
				int * IndexOfOk = new int[n];//用于记录,可以和i同为一组的数对的下标 ,以便最后可以让它们一并退出系统 
				int NumOfOk = 0;//用于记录,可以和i同为一组的数对的个数 
				result ++;//最终结果 
				IndexOfOk[NumOfOk++] = i;
				for(int j=i+1;j<=n-1;j++)//考察i之后的数对是否可以和i同一组 
				{
					if(!IsOk[j])//同样是针对没有分配的数对
					{
						if(ws[IndexOfOk[NumOfOk-1]].Weight<=ws[j].Weight)//可以和前一个同组
						{												// (思考前一个为什么不是ws[j-1]) 
							IndexOfOk[NumOfOk++] = j;//记录可以同为一组的下标 
						}
					}
				}
				for(int k=0;k<NumOfOk;k++)
					IsOk[IndexOfOk[k]] = 1;//根据之前记录的下标,让它们逐一退出系统,之后不再(不用)考虑它们了 
			}
		}
		cout << result << endl;
	}
	
	return 0;
}
上述代码提交AC.


原文地址:https://www.cnblogs.com/tensory/p/6590769.html