uva 103 - Stacking Boxes

//可以使用佳哥介绍的DAG动规,不过麻烦些

//建议使用LIS ,那么排序函数Cmp()成了以问题关键, 可以把每个box的值从左到右作为比较的关键字, 这样人为的赋予一个优先级.

由于这些集合相互之间无序,我们需要先找到一种排序方法使得这些集合的顺序满足无后效性。这牵涉到如何判断两个集合的大小。

 

 

不难想到,如果集合A<集合B,当且仅当将集合A、B中的元素分别升序排列后,满足Ai<Bi。不难证明。

有了上面这条性质,我们可以按以下规则进行排序:先将所有集合中的元素分别排序,然后将第一个元素作为第一关键字,第二个元素作为第二关键字....依此类推,排序之。

容易知道这样整个序列就满足无后效性了,可以用最长不下降序列解决之。

//注意LIS和"无后效性"的关系

//无后效性://无后效性   //无后效性是一个问题可以用动态规划求解的标志之一。    //它是这样一种性质:某阶段的状态一旦确定, //则此后过程的演变不再受此前各种状态及决策的影响, //简单的说,就是“未来与过去无关”, //当前的状态是此前历史的一个完整总结, //此前的历史只能通过当前的状态去影响过程未来的演变。 //具体地说,如果一个问题被划分各个阶段之后, //阶段I中的状态只能由阶段 //I-1中的状态通过状态转移方程得来,与其它状态没有关系, //特别是与未发生的状态没有关系。 //从图论的角度去考虑,如果把这个问题中的状态定义成图中的顶点, //两个状态之间的转移定义为边, //转移过程中的权值增量定义为边的权值, //则构成一个有向无环加权图, //因此,这个图可以进行“拓扑排序”, //至少可以按它们拓扑排序的顺序去划分阶段。

#include <iostream> #include <algorithm> #include <cstdio> using namespace std; struct Box{ int len,a[12],num; bool operator < (const Box& b)const { //cout<<"UUU"<<endl; for(int i=0;i<b.len;i++) if(a[i]>=b.a[i]){ //cout<<a[i]<<" "<<b.a[i]<<endl; //cout<<b.len<<endl; return 0; } return 1; } }; int k,n,prior[35],sign[35],len,f[35],next[35],sss; Box box[35],c[35]; int bsearch(Box& v){ int l=1,r=len+1,m; while(l<r){ //cout<<l<<" "<<r<<endl; m=l+(r-l)/2; //cout<<"m: "<<m<<endl; if(c[m]<v) l=m+1; else r=m; } return l; } void LIS(){ int pos; len=1; c[len]=box[0]; sign[1]=0; for(int i=1;i<k;i++){ //cout<<"sda"<<endl; pos=bsearch(box[i]); c[pos]=box[i]; sign[pos]=i; prior[pos]=sign[pos-1]; if(pos>len) ++len; } } void find_res(int l,int i){ if(l==len) return ; if(l==0){ cout<<box[i].num; find_res(l+1,next[i]); return ; } cout<<" "<<box[i].num; find_res(l+1,next[i]); return ; } bool Cmp(Box i,Box j){ for(int k=0;k<j.len;k++){ if(i.a[k]!=j.a[k]){ return i.a[k]<j.a[k]; } } return 1; } int main() { freopen("i.txt","r",stdin); while(cin>>k>>n){ len=1; for(int i=0;i<k;i++){ for(int j=0;j<n;j++){ cin>>box[i].a[j]; } box[i].len=n; box[i].num=i+1; sort(box[i].a,box[i].a+n); } sort(box,box+k,Cmp); // for(int i=0;i<k;i++){ // for(int j=0;j<box[i].len;j++) // cout<<box[i].a[j]<<" "; // cout<<endl; // } f[k-1]=1; for(int i=k-2;i>=0;i--){ f[i]=1; for(int j=i+1;j<k;j++) if(box[i]<box[j]&&f[i]<f[j]+1){ f[i]=f[j]+1; next[i]=j; if(f[i]>len){ len=f[i]; sss=i; } } } cout<<len<<endl; find_res(0,sss); cout<<endl; } return 0; }

你可能感兴趣的:(c)