05年论文题
话说很久之前做拦截导弹的时候狮看的题解
题解说第二问求最长上升子序列
当时并不明白
就混过去了(当然贪心也可做啊)
今天才知道
原来有个东西叫Dilworth定理
最小分解链数=最长反链长度
然后这道题就可以运用论文中的特别技巧过掉了
然而还有个问题
我不太清楚POI的官网要怎么交题
不过有这个
但是这里也没法交TAT反正我交了之后它一直显示等待编译
然后发现。。。
下面有数据!
自己测了下
都过了wakaka
所以算是理论上1A了吧
感觉偏序好好玩
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=5000+5;
struct Edge{
int from,to;
};
vector<Edge>e;
vector<int>g[N];
int f[N*N];
void addedge(int u,int v){
e.push_back((Edge){u,v});
g[u].push_back(e.size()-1);
}
int pre[N],vis[N];
pair<int,int> back(int u){
int ans=0;
do{
ans=max(ans,f[pre[u]]);
u=e[pre[u]].from;
}while(vis[u]!=1);
return make_pair(u,ans+1);
}
void refresh(int u,pair<int,int> ans){
do{
f[pre[u]]=ans.second;
u=e[pre[u]].from;
}while(u!=ans.first);
}
void dfs(int u){
vis[u]=1;
for(int i=0;i<g[u].size();i++){
int v=e[g[u][i]].to;
f[g[u][i]]=1;
if(!vis[v]){
pre[v]=g[u][i];
dfs(v);
}
else{
pair<int,int>ans=back(v);
pre[v]=g[u][i];
refresh(v,ans);
}
}
vis[u]=2;
}
int main(){
freopen("a.in","r",stdin);
int n;scanf("%d",&n);
for(int i=1;i<n;i++){
int k;scanf("%d",&k);
int v;
for(int j=1;j<=k;j++){
scanf("%d",&v);
addedge(i,v);
}
}
dfs(1);
int ans=0;
for(int i=0;i<e.size();i++)
ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}