POJ 1065 贪心+链-反链-Dilworth定理的应用+ POJ3636 排序方案的不同

7 篇文章 0 订阅

Wooden Sticks

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 26050 Accepted: 11277

Description

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 ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , and ( 4 , 1 ) , then the minimum setup time should be 2 minutes since there is a sequence of pairs ( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) , ( 1 , 2 ) , ( 2 , 5 ) .

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 2n 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 1 

Sample Output

2
1
3

Source

附赠一组数据

7
4
85 74 56 25 10 30 98 81 
2
53 28 34 59 
6
35 82 57 36 5 2 84 40 44 58 87 19 
6
66 78 60 35 51 72 34 56 98 78 33 100 
3
22 62 7 22 59 59 
9
38 63 69 75 90 35 33 77 77 74 42 84 10 55 72 40 29 36 
8
51 24 23 24 35 20 79 32 79 58 37 14 86 10 16 36 

answer

2
2
4
3
2
4
5

开始写了一段贪心的代码,先附上作为反例吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    int l,w;
    bool operator < (const node &a)const{
        if(a.l==l)
            return a.w>w;
        return a.l>l;
    }
}num[5002];
int dp[5002];
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define init(a,b) memset(a,b,sizeof a)
bool vis[5002];
int main(){
    int n,k;
    int T;
    scanf("%d",&T);
    while(T--){
    scanf("%d",&n);
    init(vis,false);
    rep(i,1,n)
    scanf("%d%d",&num[i].l,&num[i].w);
    sort(num+1,num+1+n);
    int f=0;
    int cont=0;
    rep(i,1,n)
    rep(j,i+1,n)
    {
        if(!vis[j]&&num[i].l<=num[j].l&&num[i].w<=num[j].w)
            vis[j]=true;
    }
    int ans=0;
    rep(i,1,n)
    if(!vis[i]) ans++;
    printf("%d\n",ans);
    }
    return 0;
}

开始肯定是需要排序的,然后我错误的思路就是将每一组数据依次和后面的数据对比,满足条件就标记为1,但是这种思路过上面另一组数据就错了,没有考虑到这种情况,这道题贪心解决的时候是需要记录当前点的

下面是参考大牛的思路写出的https://www.cnblogs.com/fstang/archive/2013/03/31/2991255.html

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    int l,w;
    bool operator < (const node &a)const{
        if(a.l==l)
            return a.w>w;
        return a.l>l;
    }
}num[5002],dp[5002];

const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define init(a,b) memset(a,b,sizeof a)
bool vis[5002];
int main(){
    int n,k;
    int T;
    scanf("%d",&T);
    while(T--){
    scanf("%d",&n);
    init(vis,false);
    rep(i,1,n)
    scanf("%d%d",&num[i].l,&num[i].w);
    sort(num+1,num+1+n);
    int f=0;
    int cont=0;
    rep(i,1,n){
        f=0;
    rep(j,1,cont)
    {
        if(num[i].l>=dp[j].l&&num[i].w>=dp[j].w)
            {dp[j]=num[i];f=1;break;}
    }
    if(!f) dp[++cont]=num[i];
    }

    printf("%d\n",cont);
    }
    return 0;
}

下面是TLE的3636,如果将下面的方法改为上面1065的就能AC了

//这一题和poj1065的唯一的一处差别就是poj1065要求l'>=l&&w'>=w;
//但在poj3636这一道题目中就是把等号给去掉了,那就需要改动一下排序了,先说下改动的地方
//就是先排l,从小到大排列,然后再排w从大到小排列,为什么?先上一组数据 4  1 2 1 3 2 4 3 3
//如果是按照1065的方法排列的话,最后的排序就是上面的一组数据,模拟一下发现最后的答案是3,多了一个
//由于这样排列使得 1 2这个数据被2 4覆盖了,本来3 3是可以接到1 2的后面,但是只能另开一个空间,因此
//答案就多了一个。w从大到小排列就不会出现覆盖的情况了,这一点很难想到,坑。。。。。。。。。 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    int l,w;
    bool operator < (const node &a)const{
        if(a.l==l)
            return a.w<w;
        return a.l>l;
    }
}num[20010],dp[20010];
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define init(a,b) memset(a,b,sizeof a)
bool vis[20020];
int main(){
    int n,k;
    int T;
    scanf("%d",&T);
    while(T--){
    scanf("%d",&n);
    rep(i,1,n)
    scanf("%d%d",&num[i].l,&num[i].w);
    init(vis,false);
    sort(num+1,num+1+n);
    int f=0;
    int cont=0;
    rep(i,1,n){
        if(!vis[i]){
                int minl=num[i].l;
        int minw=num[i].w;
    rep(j,1+i,n)
    {
        if(!vis[j]&&num[j].l>minl&&num[j].w>minw)
            {
                minl=num[j].l;minw=num[j].w;vis[j]=1;
            }
    }
    }
    }
    rep(i,1,n)
    if(!vis[i]) cont++;
    printf("%d\n",cont);
    }
    return 0;
}

再来一种通过二分的思路解决的


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    int l,w;
    bool operator < (const node &a)const{
        if(a.l==l)
            return a.w<w;
        return a.l>l;
    }
}num[20010],dp[20010];
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define init(a,b) memset(a,b,sizeof a)
bool vis[20020];
int reasech(node a,int len)
{
    int r=len;
    int l=1;
    while(l<=r)
    {
        int mid=(l+r)>>1;//dp数组是从大到小的排列顺序
        if(dp[mid].w<a.w) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main(){
    int n,k;
    int T;
    scanf("%d",&T);
    while(T--){
    scanf("%d",&n);
    rep(i,1,n)
    scanf("%d%d",&num[i].l,&num[i].w);
    sort(num+1,num+1+n);
    int cont=0;
    rep(i,1,n){
     int temp=reasech(num[i],cont);
     if(cont+1==temp) dp[++cont]=num[i];
     else dp[temp]=num[i];
    }
    printf("%d\n",cont);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值