矩形嵌套问题
https://www.luogu.com.cn/problem/CF4D
把每个矩形看成一个点,如果一个矩形X能嵌套在矩形Y里面,就可以从X到Y连一条有向边
这样一个有向无环图就建立起来了
设dp[u]表示从u节点出发能够到达的最大长度。
状态转移方程:d[u]=max{d[v]+1|(u,v)€E}
方法1,构建DAG,深搜
#include <iostream>
using namespace std;
struct Rect
{
int w;
int h;
int id;
};
const int MAXN = 5001;
bool g[MAXN][MAXN];
Rect rect[MAXN];
int dp[MAXN];
int cnt = 0;
int f(int u)
{
//为表项dp[u]声明一个引用res, 任何对res的读写实际上都是在对dp[u]进行
int& res = dp[u];
if (res > 0)
return res;
res = 1;
for (int v = 0; v < cnt; ++v)
if (g[u][v])
res = max(res, f(v)+1);
return res;
}
void printpath(int u)
{
cout << rect[u].id << " ";
for (int v = 0; v < cnt; ++v)
if (g[u][v] && dp[u] == (dp[v]+1))
{
printpath(v);
break;
}
}
int main()
{
int i, j, t, W, H, tmp = -1, width, height, n;
cin >> n >> W >> H;
for (i = 1; i <= n; ++i)
{
cin >> width >> height;
if (width > W && height > H)
{
rect[cnt].w = width;
rect[cnt].h = height;
rect[cnt++].id = i;
}
}
if (cnt == 0)
{
cout << 0 << endl;
return 0;
}
// Create DAG
for (i = 0; i < cnt; ++i)
for (j = 0; j < cnt; ++j)
if (rect[i].h < rect[j].h && rect[i].w < rect[j].w)
g[i][j] = true;
int res = 0;
for (i = 0; i < n; ++i)
{
tmp = f(i);
if (res < tmp)
{
res = tmp;
t = i;
}
}
cout << res << endl;
printpath(t);
cout << endl;
return 0;
}
方法二: 先排序,在DP
#include <iostream>
#include <stdlib.h>
using namespace std;
struct Rect
{
int w;
int h;
int id;
};
const int MAXN = 5001;
Rect rect[MAXN];
int dp[MAXN];
int from[MAXN];
int cnt = 0;
int cmp(const void *a, const void *b)
{
return ((Rect *)a)->w - ((Rect *)b)->w;
}
void printpath(int u)
{
for (int v = 0; v < cnt; ++v)
if (dp[u] == (dp[v]+1))
{
printpath(from[u]);
break;
}
cout << rect[u].id << " ";
}
int main()
{
int i, j, t, W, H, width, height, n;
cin >> n >> W >> H;
for (i = 1; i <= n; ++i)
{
cin >> width >> height;
if (width > W && height > H)
{
rect[cnt].w = width;
rect[cnt].h = height;
rect[cnt++].id = i;
}
}
if (cnt == 0)
{
cout << 0 << endl;
return 0;
}
for (i = 0; i < cnt; ++i)
{
from[i] = -1;
dp[i] = 1;
}
// 按照宽,升序排列,外层物品的宽度大于内层物品的宽度
qsort(rect, cnt, sizeof(Rect), cmp);
for (i = 1; i < cnt; ++i)
for (j = 0; j < i; ++j)
if (rect[i].h > rect[j].h && rect[i].w > rect[j].w && (dp[j]+1) > dp[i])
{
dp[i] = dp[j] + 1;
from[i] = j;
}
int res = 0;
for (i = 0; i < n; ++i)
{
if (res < dp[i])
{
res = dp[i];
t = i;
}
}
cout << res << endl;
printpath(t);
cout << endl;
return 0;
}
长方体搭塔,求最塔的最大高度
/* https://vjudge.csgrandeur.cn/problem/UVA-437 */
#include <iostream>
#include <set>
using namespace std;
struct Block
{
Block(int ll, int ww, int hh) : l(ll), w(ww), h(hh) {}
// ascending order
bool operator<(const Block &p) const
{
return p.l > l || (p.l == l && p.w > w) || (p.l == l && p.w == w && p.h > h);
}
int l; // length
int w; // width
int h; // height
};
int dp[100];
int main()
{
int i, j, n, L, W, H, cnt = 0, ans;
while (cin >> n && n > 0)
{
++cnt;
set<Block> blocks;
for (i = 0; i < n; ++i)
{
cin >> L >> W >> H;
if (L > W)
blocks.insert(Block(L, W, H));
else
blocks.insert(Block(W, L, H));
if (W > H)
blocks.insert(Block(W, H, L));
else
blocks.insert(Block(H, W, L));
if (L > H)
blocks.insert(Block(L, H, W));
else
blocks.insert(Block(H, L, W));
}
i = 0;
for (auto iter = blocks.begin(); iter != blocks.end(); ++iter, ++i)
{
dp[i] = iter->h;
}
auto iter1 = blocks.begin();
++iter1;
i = 1;
ans = dp[0];
for (; iter1 != blocks.end(); ++iter1, ++i)
{
j = 0;
for (auto iter2 = blocks.begin(); j < i && iter2 != blocks.end(); ++iter2, ++j)
{
if ((iter1->l > iter2->l) && (iter1->w > iter2->w) && (dp[i] < dp[j] + iter1->h))
{
dp[i] = dp[j] + iter1->h;
}
}
if (ans < dp[i])
ans = dp[i];
}
cout << "Case " << cnt << ": maximum height = " << ans << endl;
}
return 0;
}