CF这套题目确实水啊,这题把每个信封能套进去的信封n方扫一遍,然后连一条有向边。由于一个信封不可能直接或间接地套在自己身上,因此这个图是一个DAG(有向无环图)。设f(i)表示从节点0开始的最多的矩形嵌套,就变成了求DAG上最长路的水题。f(i)=max(f(i),f(v)|(i,v)属于E)E是边集。
这坑爹题我交了两遍,第一次MLEon32,一看就是Vector爆了,考虑到只有5000个信封,果断short开起,然后就一半多一点的内存A了,辛亏不用写邻接表。
记录方案的话设一个from(i)表示i是由哪个推过来的,迭代输出就行了。
伏地%__debug大神。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
const int MAXN=5005;
struct card{
int w,h;
}Karte[MAXN];
int n,dp[MAXN],from[MAXN];
std::vector<short> G[MAXN];
void add(short a,short b)
{
G[a].push_back(b);
}
int Memorized_Search(short u)
{
if(dp[u])return dp[u];
if(!G[u].size())
{
dp[u]=0;
return 0;
}
int& ans=dp[u];
for(int i=0;i<G[u].size();i++)
{
int k=Memorized_Search(G[u][i])+1;
if(dp[u]<k)
{
dp[u]=k;
from[u]=G[u][i];
}
}
return dp[u];
}
int main()
{
scanf("%d",&n);
scanf("%d %d",&Karte[0].w,&Karte[0].h);
for(int i=1;i<=n;i++)
scanf("%d %d",&Karte[i].w,&Karte[i].h);
for(int i=0;i<=n;i++)
{
int x=Karte[i].w,y=Karte[i].h;
for(int j=0;j<=n;j++)if(i!=j)
{
int a=Karte[j].w,b=Karte[j].h;
if(x<a&&y<b)add(i,j);
}
}
memset(dp,0,sizeof(dp));
Memorized_Search(0);
int root=from[0];
printf("%d\n",dp[0]);
while(root)
{
printf("%d ",root);
root=from[root];
}
}