CodeForces 4D
我看了看大部分题解是按照 \(\mathcal{DP}\) 做的呢。
然鹅本羸弱根本对 \(\mathscr{DP}\) 一窍不通。
所以自己 \(\mathcal{YY}\) 另一种清奇的做法。
每次我们将两个符合条件的点 \(x(i,j),y(i,j) (x_i<y_i,x_j<y_j)\) 建一条边
从 \(x\) 指向 \(y\) 。
显然在把所有点加入后,至少存在一个点入度为零。
所以我们只要拓扑排序,每次记录当前最长值,最后 \(dfs\) 输出方案就好了。
值得注意的是: 这道题需要的空间比较大。 所以我们要使用邻接矩阵。
因为邻接表是邻接矩阵空间的 \(2\) 倍加 \(N\) (记录一个点二倍, \(head\) 是 \(N\) )
其次邻接矩阵类型要使用 \(bool\) ,不然照样 \(\mathcal{MLE}\)
下面是 \(\mathcal{\color{green}{AC}}\) 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
using namespace std;
#define ri register int
bool mat[5002][5002];
int len[5002], pre[5002], id[5002];
int wf[5002], hf[5002], in[5002];
int n, w, h, cnt, cnte, ans, fin;
inline void topo()
{
queue<int> bf;
for (ri i = 1; i <= cnt; ++i)
if (in[i] == 0) bf.push(i), len[i] = 1;
while (!bf.empty())
{
int now = bf.front();
bf.pop();
if (ans < len[now])
{
ans = len[now];
fin = now;
}
for (ri i = 1; i <= cnt; ++i)
{
if (i == now || !mat[now][i]) continue;
--in[i];
if (len[i] < len[now] + 1)
len[i] = len[now] + 1, pre[i] = now;
if (in[i] == 0)
bf.push(i);
}
}
}
void dfs(int p)
{
if (p == 0) return;
if (pre[p]) dfs(pre[p]);
printf("%d ", id[p]);
}
int main()
{
scanf("%d%d%d", &n, &w, &h);
for (ri i = 1; i <= n; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
if (x <= w || y <= h) continue;
wf[++cnt] = x, hf[cnt] = y;
id[cnt] = i;
}
if (cnt == 0)
{
printf("0\n");
return 0;
}
for (ri i = 1; i < cnt; ++i)
for (ri j = i + 1; j <= cnt; ++j)
{
if (wf[i] < wf[j] && hf[i] < hf[j])
mat[i][j] = 1, ++in[j];
else if (wf[i] > wf[j] && hf[i] > hf[j])
mat[j][i] = 1, ++in[i];
}
topo();
printf("%d\n", ans);
dfs(fin);
return 0;
}