• 【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.


  • 相关阅读:
    day06-Java方法和数组(二)
    day05作业-----------Java方法和数组
    day01作业-------------Java概述
    day04--Java流程控制
    获取数据库连接对象的方法
    oracle数据库时间的处理
    把页面获得的String格式的时间转换成date存入到数据库
    复选下拉菜单
    log4j实现日志记录(搬运)
    js点击按钮打开下拉菜单,再次点击关闭的简单办法
  • 原文地址:https://www.cnblogs.com/tensory/p/6590769.html
Copyright © 2020-2023  润新知