문제 원본
난이도 : M
Background
//해석이 잘 안되는 관계로 생략을...(문제 푸는데에는 지장이 없습니다.)
The problem
n차원으로 이루어진 박스가 주어집니다. 2차원으로 이루어진 박스 (2,3)은 길이가 2와 너비가 3인 박스이다. 3차원 박스인 (4,8,9)는 4x8x9 (길이,넓이 그리고 높이)를 나타낸다. 그리고 6차원 박스인 (4,5,6,7,8,9) 명확하진 않지만..뭐 계산 할 수 있다. (?)
이 문제에서 너는 n차원의 박스들의 특성을 분석할 것이다. 너는 가장 많이 포갤 수 있는 상자들을 결정해야 한다. (상자 안에 상자를 넣는 것 같습니다.)
박스를 포개는 방법은 각 박스를 구성하는 요소들이 한 박스가 다른 박스보다 전부 작다면 포갤 수 있다. (이 조건을 만족시키기 위해 각 박스들을 구성하는 요소들을 재 배열 할 수 있다.)
예를 들어 박스 D가 (2,6)이고 E가 (7,3)이라면 ... 이 상태로는 포갤 수 없겠지만 D를 (6,2)로 바꾸거나 E를 (3,7)로 바꾼다면 박스를 포갤 수 있다. 또 박스 D가 (9,5,7,3)이고 E가 (10,4,6,8)이라면 D를 (9,3,5,7)로 재 배열하면 포갤 수 있다.
이럴 때 가장 많은 박스들이 포갠 수와 가장 안에 있는 박스들 순서대로 출력한다.
input
첫줄에 박스들의 수와 차원이 주워진 후
그 다음 줄 n개(박스의 수)만큼 m(차원)의 숫자가 주어진다.
n <= 30 이고 m <= 10입니다.
output
가장 많은 박스들이 포갠 수와 가장 안에 있는 박스들 순서대로 출력한다.
Sample Input
5 2
3 7
8 10
5 2
9 11
21 18
8 6
5 2 20 1 30 10
23 15 7 9 11 3
40 50 34 24 14 4
9 10 11 12 13 14
31 4 18 8 27 17
44 32 13 19 41 19
1 2 3 4 5 6
80 37 47 18 21 9
Sample Output
5
3 1 2 4 5
4
7 2 5 6
Solution
dynamic프로그래밍으로 문제가 쉽게 풀립니다.
그것도 1차원 다이나믹 프로그래밍으루요;
박스의 차원이 계속 늘어나기 때문에 상당히 어렵게 생각 할 수도 있는데 뭔가 Fake같은 겁니다.
일단 다이나믹의 부분문제를 쓰자면
D[i] = i 상자를 포갰을 때의 최대 길이
D[i] = if( G(i,j) == 1 )
max { D[j] }
j = 1 ~ i-1; G(i,j) 는 i가 j를 쌓을 수 있을 때 1를 리턴 아니면 0을 리턴
요런 식으로 해주시면 됩니다. (다이나믹 자체는 그다지 어렵지 않다고 생각합니다.
그럼 이제 저 함수 G가 문제되는데요...이 부분은 생각보다 매우 간단합니다. (저도 쪼금 해맸는데 ㅎ;;)
결론부터 말하자면 박스 i와 박스 j를 구성하는 숫자들을 정렬해 준후 순서대로 따지다가 박스 i의 숫자가 박스 j의 수보다 작다면 바로 리턴 0을 해주시면 됩니다.
이게 가능한 이유가
박스 i의 구성하는 숫자들을
i1 , i2 , i3 , i4 ... in (정렬 되어있다고 가정합니다.)
또 박스 j를 구성하는 숫자들을
j1 , j2 , j3, j4 ... jn이라고 하면
만약 어느 x지점에서 i의 숫자가 j의 숫자보다 작다고 해봅시다.
ix < jx 라고 가정한다면...jx를 커버 할 수 있는 숫자를 구하기 위해 ix+1를 가져와야만 할 것입니다. 그런데
ix+1를 가져오면요?;; jx+1를 커버할 수 있는 숫자가 없어집니다. 그럼 ix+2를 가져오고 등등 ... 가다보면 결국엔
jn을 커버할 수 있는 숫자가 없어지게 됩니다. 결국엔 둘의 값을 정렬해놓고 한개라도 커버할 수 없다면 둘은 서로 포개질 수
없는 상자가 되는 거지요...
Source
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using std::sort;
using std::stable_sort;
const int N_MAX = 33;
const int M_MAX = 13;
struct fs{
int first[M_MAX+5];
int second;
};
fs a[N_MAX+5];
int chase[N_MAX + 5];
int dynamic[N_MAX + 5],n,m;
int print[N_MAX + 5],pcnt;
struct comp{
bool operator () (const fs &fi , const fs &se){
int j;
for(j=m;j>=1;j--){
if(fi.first[j] != se.first[j])
return fi.first[j] < se.first[j];
}
return 1;
}
}_comp;
struct comp_st{
bool operator () (const int &fi, const int &se){
return fi > se;
}
}_comp_st;
int judge_can_pile(int p,int q)
{
int i;
for(i=1;i<=m;i++){
if(a[p].first[i] >= a[q].first[i])
return 0;
}
return 1;
}
void Aruray_Mirgon()
{
//freopen("input.txt","rt",stdin);
//freopen("output.txt","wt",stdout);
int i,j,max,t,q,k;
int temp[M_MAX+5];
while(scanf("%d %d",&n,&m) == 2){
memset(dynamic,0,sizeof(dynamic));
memset(chase,0,sizeof(chase));
for(i=1;i<=n;i++){ // box 수
a[i].second = i; // number
for(j=1;j<=m;j++){ // 차원
scanf("%d",&a[i].first[j]);
}
//구성요소들을 정렬 해주기...
for(j=1;j<=m;j++){
for(k=j+1;k<=m;k++){
if(a[i].first[j] > a[i].first[k]){
t = a[i].first[j];
a[i].first[j] = a[i].first[k];
a[i].first[k] = t;
}
}
} // bubble...
//근데 왜 여기서 STL _ sort 가 듣지 않는지 이해가 가질 않음 =ㅁ=;
// 왜 안되는지 아시는 분은 http://arubirate.tistory.com으로 해결 방법좀요...
//sort(a[i].first+1,a[i].first+m,_comp_st);
}
sort(a+1,a+n+1,_comp);
/*for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
printf("%d ",a[i].first[j]);
}
printf("\n");
}*/
//DP부분
dynamic[n] = 1;
chase[n] = -1;
for(i = n-1; i >= 1; i--){
max = 1; q = -1;
for(j = i+1; j <= n; j++){
t = judge_can_pile(i,j);
if(t == 1){
if(max < dynamic[j]+1){
q = j; max = dynamic[j] + 1;
}
}
}
dynamic[i] = max;
chase[i] = q;
}
//
//역추적
max = -1;
for(i=1;i<=n;i++){
if(dynamic[i] > max){
q = i; max = dynamic[i];
}
}
printf("%d\n",max);
pcnt = 0;
while(q != -1){
print[pcnt++] = a[q].second;
q = chase[q];
}
//
for(i=0;i<pcnt-1;i++)
printf("%d ",print[i]);
printf("%d",print[pcnt-1]);
printf("\n");
}
}
void main()
{
Aruray_Mirgon();
}