ACM题解——贪心之木头加工
题目描述
There is a pile of n wooden sticks. The length and weight of each stick are known in advance. The sticks are to be processed by a woodworking machine in one by one fashion. It needs some time, called setup time, for the machine to prepare processing a stick. The setup times are associated with cleaning operations and changing tools and shapes in the machine. The setup times of the woodworking machine are given as follows:
(a) The setup time for the first wooden stick is 1 minute.
(b) Right after processing a stick of length l and weight w , the machine will need no setup time for a stick of length l' and weight w' if l<=l' and w<=w'. Otherwise, it will need 1 minute for setup.
You are to find the minimum setup time to process a given pile of n wooden sticks. For example, if you have five sticks whose pairs of length and weight are (4,9), (5,2), (2,1), (3,5), and (1,4), then the minimum setup time should be 2 minutes since there is a sequence of pairs (1,4), (3,5), (4,9), (2,1), (5,2).
Input
The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case consists of two lines: The first line has an integer n , 1<=n<=5000, that represents the number of wooden sticks in the test case, and the second line contains n 2 positive integers l1, w1, l2, w2, ..., ln, wn, each of magnitude at most 10000 , where li and wi are the length and weight of the i th wooden stick, respectively. The 2n integers are delimited by one or more spaces.
Output
The output should contain the minimum setup time in minutes, one per line.
Sample Input
3 5 4 9 5 2 2 1 3 5 1 4 3 2 2 1 1 2 2 3 1 3 2 2 3 1Sample Output
2 1 3
题目大意
给n根木头,加工第一根1min,当后面的木头长宽都大等前面一根时,加工时间为0min,否则加工时间为1min;分别给出这n根木头长和宽,求加工所需的最短时间。
题解
开始我的思路是木头存放在一个结构体中,结构体按照长宽都最小的排到最前面,后面只能排长宽都比前一个大的,直到排完之后然后排长宽有交错(长宽有一个大于前面,有一个小于前面),再次进行同样的排序,然后从前往后找,找到交错的位置就时间加1,但是结构体排序无法实现这样的排序方式就是无法将交错的木头放到最后。因此需要手动实现:
首先现将结构体按长(或宽)从小大到大排序,结构体中除了存放这根木头的长和宽,还要存放访问标记,初始化为0(未访问);然后用for循环从前往后找,找到第一个标记为0的点,把标记改为已访问,时间计数器加一,并设置当前长curr_L和当前宽curr_W,从这个点开始,凡是后面木头访问标记为0且长宽都大于当前长curr_L和当前宽curr_W的,就把其访问标记设为已访问,然后当前长curr_L和当前宽curr_W更新为这个木头的长和宽,直到所有木头都遍历;一圈扫完之后就是完成了以第一个最小木头打头的双递增排列。
然后跳出内层循环,再次进入外层循环,继续寻找当前第一个访问标记为0的木头,其实就是那些没有被加入上一个双递增排列的木头,开始第二个双递增排列,以这个木头为头,从其后面开始再次内循环,重复上面的操作即可。直到外层循环找不到标记点为0的木头就结束,输出计数器的值即为答案。
代码
#include<iostream>
#include<algorithm>
using namespace std;
struct wood
{
int len;
int wid;
int add;
};
bool cmp2(wood x,wood y)
{
if(x.len==y.len)
return x.wid<y.wid;
else
return x.len<y.len;
}
int main()
{
int t=0;
cin>>t; //t个case
for(int i=0;i<t;i++)
{
int n=0;
cin>>n;
wood *mt=new wood[n];
que *Q=new que[n];
bool *book=new bool[n]; //可以把访问标记直接放到结构体里面
for(int j=0;j<n;j++)
{
cin>>mt[j].len>>mt[j].wid;
book[j]=0;
}
sort(mt,mt+n,cmp2);
int cur_l=0,cur_w=0,coun=0;//当前长、宽和时间计数器
for(int k=0;k<n;k++)
{
if(book[k]==0)
{
cur_l=mt[k].len;
cur_w=mt[k].wid;
book[k]=1;
coun++;
for(int j=k+1;j<n;j++)
{
if(book[j]==0 && mt[j].len>=cur_l && mt[j].wid>=cur_w)
{
cur_l=mt[j].len;
cur_w=mt[j].wid;
book[j]=1;
}
}
}
}
cout<<coun<<endl;
}
return 0;
}