【贪心】【DP】【Dilworth's theorem】 POJ 1065 Wooden Sticks

【贪心】【DP】【Dilworth's theorem】 POJ 1065 Wooden Sticks

题目连接:
http://poj.org/problem?id=1065
题目大意:
有一堆树,每棵树有两个属性:(w,l),求把这些树按照某种次序排列后的最小
setup time ,
定义当!( wi < w i+1 && li < li+1)时,消耗一个setup time
(表达的不好,见谅)

分析:
Dilworth's theorem
参考
http://hi.baidu.com/lambda2fei/blog/item/6001f64476ae852acffca3be.html Orz 

 

Dilworth定理说的是:对于一个偏序集,其最少链划分数等于其最长反链的长度。
Dilworth定理的对偶定理说的是:对于一个偏序集,其最少反链划分数等于其最长链的长度。

Dilworth定理先不证,有空再不上来,其对偶定理证明如下:
设一个偏序集S的最少反链划分数是p,最长链长度是r。
1.先证p≥r。这是显然的,因为最长链长度是r,r个元素中的任意两个都可以比较,因此它们必定两两属于不同的反链,因此反链个数≥r,即p≥r。

2.再证r≥p。设X1=S。找出X1的所有极小元组成集合Z1,将其从X1删之,得到X2,再找出X2的所有极小元组成集合Z2(特别注意Z2中的任何元素a2,在X1中必然存在一个元素a1使得a1≤a2,否则a2可以放到X1中,这与X1的选取矛盾),再将Z2从X2中删除,得到X3,……这样一直下去,总存在一个k使得XK不空但X(K+1)为空。这样便得到一条链a1,a2,a3,……,ak,其中ai属于Xi。由于r是最长链长度,因此r≥k。另一方面,我们也得到了一个反链划分,即X1,X2,X3,……,XK。由于p是最少反链划分,因此k≥p。因此有r≥p。证毕。

这个题目的解就是这个定理证明的过程,
本题直接找最长反链就行了



直接排序方法:

#include <cstdio>
#include 
<algorithm>

using namespace std;

const int MAXN = 5010;
int n;

struct Node
{
    
int l;
    
int w;
};

Node data[MAXN];
bool visit[MAXN];

bool mcmp(Node a,Node b)
{
    
if(a.l != b.l ) return a.l < b.l;
    
else return  a.w < b.w;
}


void init()
{
    
int i;
    scanf(
"%d",&n);
    
for(i = 0;i < n;i ++)
    {
        scanf(
"%d%d",&data[i].l,&data[i].w);
        visit[i] 
= false;
    }
    sort(data,data
+n,mcmp);
}

void work()
{
    
int tn = n;
    
int i;
    
int t = 0;
    
int j;
    
int ans = 0;
    
while(tn > 0 )
    {
        
for(i = 0;i < n;i ++)
        {
            
if(visit[i]) continue;
            visit[i] 
= true;
            tn 
--;
            t 
= i;
            j 
= i+1;
            
while(j < n )
            {
                
if(!visit[j] && data[t].l <= data[j].l && data[t].w <= data[j].w)
                {
                    visit[j] 
=  true;
                    tn 
--;
                    t 
= j;
                }
                j 
++;
            }
            ans 
++;
        }
    }
    printf(
"%d\n",ans);

}



int main()
{
    
int cas;
    scanf(
"%d",&cas);
    
while(cas -- )
    {
        init();
        work();
    }

    
return 0;
动态规划方法:

#include <cstdio>
#include 
<algorithm>

using namespace std;

const int MAXN =  5010;
int n;

struct Node
{
    
int l;
    
int w;
};

Node data[MAXN];
int dp[MAXN];

bool mcmp(Node a,Node b)
{
    
if(a.l != b.l ) return a.l < b.l;
    
else return a.w < b.w;
}


void init()
{
    scanf(
"%d",&n);
    
int i;
    
for(i = 0;i < n;i ++)
    {
        scanf(
"%d%d",&data[i].l,&data[i].w);
    }
    sort(data,data
+n,mcmp);
}

int max(int a,int b)
{
    
return a > b ? a : b;
}


void work()
{
    
int i;
    dp[
0= 1;
    
int m = 0;
    
int j = 0;
    
for(i = 1;i < n;i ++)
    {
        dp[i] 
= 1;
        
for(j = 0;j < i;j ++)
        {
            
if(data[i].l < data[j].l || data[i].w < data[j].w)
            {
                dp[i] 
= max(dp[i],dp[j]+1);
            }
        }
    }

    
for(i = 0;i < n;i ++)
        m 
= max(m,dp[i]);
    printf(
"%d\n",m);

}

int main()
{
    
int cas;
    scanf(
"%d",&cas);
    
while(cas -- )
    {
        init();
        work();
    }
    
return 0;
}

你可能感兴趣的:(【贪心】【DP】【Dilworth's theorem】 POJ 1065 Wooden Sticks)