Wooden Sticks
http://acm.hdu.edu.cn/diy/contest_showproblem.php?pid=1001&cid=33858
二、题目释义
给你一堆具有长度和重量的木头,让你去机器里加工,机器会有一个一分钟的set时间,首次加工需要set一次,当连续放入的木头不满足后者的长度和重量都大于等于前者时,机器需要set一下,让你求出最短的set时间(不用求出序列)
三、思路分析
我们会非常直观的想到从小到大进行排序,但很遗憾,长度和重量我们都必须考虑,我们无法对两个主元进行排序操作,但是要让机器set时间最短,其必然要满足某一个元素如长度是从小到大排序的,这是最优解的必要条件,那我们便可以对长度进行排序,对重量进行贪心。
确定使用贪心策略,最关键的有两步,一步即设计贪心策略,二即证明由贪心得到的局部最优解最优解即为整体最优解
贪心策略:排序之后扫描一遍stick,将满足条件的stick标记为vis[i] = 1,即已经被使用,不满足条件的stick为未使用,(需要注意的是当遇到不满足的stick时,扫描比较应当是比较不符合前一个与不符合后一个)扫描到尾部之后,再从第一个未使用的stick开始,扫描一遍全部未使用的stick重复之前的操作,直到全部stick都被使用,每扫描一次计数+1
证明:贪心策略所得到为每一次尽可能大的子串,每次对子串取尽可能大,所得到即为最少的子串个数
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 5005;
struct stick
{
int len,wei;
}a[N];
int vis[N];
bool cmp(stick a, stick b)
{
if(a.len == b.len)
return a.wei < b.wei;
else return a.len < b.len;
}
int main()
{
int T,n; cin >> T;
int flag;
while(T--)
{
memset(vis,0,sizeof(vis));
for(int i=0; i<n; i++)
scanf("%d%d",&a[i].len,&a[i].wei);
sort(a,a+n,cmp);
for(int i=0; i<n; i++)
{
printf("%d %d ",a[i].len,a[i].wei);
}
cout << endl;
int st=0, cnt=0;
vis[0] = 1;
while(st<n)
{
cnt++; flag = 1;
for(int j=st,i=st+1; i<n; i++)
{
if(vis[i]) continue;
if(a[j].wei<=a[i].wei)
{ vis[i] = 1;
j = i; // 这一步实现,只有符合了条件,比较的stick才会依次向前迭代
}
else
{
if(flag) // 这里的flag用来确定只有在这一遍扫描中,只有第一个未使用的会被标记st,以作为下一次的起点
{
st = i;
flag = 0;
}
}
}
if(flag) break;
}
cout << cnt << endl;
}
return 0;
}