传送门:bzoj1143
题解
在r_64的uoj博客中看到这题原本有三个问题:
1)最长反链的长度;
2)一个最长反链;
3)哪些元素可能在最长反链中。
第一问(也就是题目中的问题)即求图的最长反链。
下面先介绍一些关于 D A G DAG DAG的概念,以及之间的关系。
二分图?简单来说就是没有奇环的图。
Dilworth定理
偏序集
设 P P P为集合, P P P上的二元关系 ≤ \leq ≤满足:
- 自反性: x ≤ x x\leq x x≤x
- 反对称性: a ≤ b , b ≤ a → a = b a\leq b,b\leq a\to a=b a≤b,b≤a→a=b
- 传递性: a ≤ b , b ≤ c → a ≤ c a\leq b,b\leq c\to a\leq c a≤b,b≤c→a≤c
则称 ≤ \leq ≤是 P P P上的偏序关系。具有偏序关系的集合 P P P称为偏序集,记为 ( P , ≤ ) (P,\leq) (P,≤)。
若 a ≤ b a\leq b a≤b或 b ≤ a b\leq a b≤a,则称 a , b a,b a,b是可比的,否则就称 a , b a,b a,b是不可比的,记作 a ∣ ∣ b a||b a∣∣b。
-----摘自百度百科
链
链:
P
P
P的子集,满足集合中任意两不同元素可比。
反链:
P
P
P的子集,满足集合中任意两不同元素不可比。
(这里的链不仅指图上的链,是更广泛的数学概念)
对偶定理
- P P P的链划分最少集合,等于其最长反链长度。
- P P P的反链划分最少集合,等于其最长链长度。
最长反链=最小链覆盖
这个结论显然就可以由上面的对偶定理得到了。
D
A
G
DAG
DAG中的偏序关系定义为:若点
a
a
a可以通过图上有向边到达点
b
b
b或点
b
b
b可到达点
a
a
a,
a
,
b
a,b
a,b即是可比的,否则不可比。
最长反链的点集中任意两点不可比。
最小链覆盖就是将
D
A
G
DAG
DAG划分成链的最少链数。
DAG的各种概念与二分图上的结论
概念
- 最大匹配: D A G DAG DAG中边集 E E E中任意两条边没有公共顶点。
- 最小点覆盖: D A G DAG DAG中最小的点集 S S S满足 D A G DAG DAG中每条边至少有一个顶点 ∈ S \in S ∈S。
- 最大点独立集: D A G DAG DAG中最大的点集 S S S满足点集中任意不同的两个顶点不共用一条边。
- 最大团: D A G DAG DAG中的最大点集 S S S满足集合中任意不同的两个顶点之间有连边。
结论
这些概念搬到二分图上后,产生了一些特殊的性质。
- 二分图最小点覆盖=二分图最大匹配数
- D A G DAG DAG最小链覆盖数= D A G DAG DAG节点数-对应二分图最大匹配数
- 最大点独立集= D A G DAG DAG节点数-对应二分图
- 二分图的最大团=补图的最大点独立集
具体证明及构造方法
详见推荐博文:二分图的最小顶点覆盖 最大独立集 最大团-将狼踩尽 19891101
有了这些结论,就可以轻松解决第一问了。
构造最长反链
设二分图中
x
(
a
)
,
y
(
a
)
x(a),y(a)
x(a),y(a)分别表示顶点
a
a
a在
X
,
Y
X,Y
X,Y部中的点。
在构造二分图求出最大点独立集
I
I
I后,若
x
(
a
)
∈
I
,
y
(
a
)
∈
I
x(a)\in I,y(a)\in I
x(a)∈I,y(a)∈I,则
a
a
a在最长反链上。而r-64的题解中也证明了这样构造出的反链是最长的。
判断点出现可能
至于最后一个问题,只需要枚举每个点,在将与当前点可比的点(包括该点本身)全部删去后的二分图跑最大匹配,若恰比答案少1,则该点能够出现在最长反链上。
代码
#include<bits/stdc++.h>
#define RI register
using namespace std;
const int N=105;
int n,m,num,ans,bel[N],in[N];
int g[2][N][N],nw,used[N],res[N];
inline bool dfs(int x)
{
RI int i;
for(i=1;i<=num;++i)
if(!used[i] && g[nw][x][i]){
used[i]=1;
if(!bel[i] || dfs(bel[i])){
bel[i]=x;return true;
}
}
return false;
}
inline int maxmatch()
{
RI int i,re=0;
memset(bel,0,sizeof(int)*(n+3));
for(i=1;i<=num;++i){
memset(used,0,sizeof(int)*(num+3));
if(dfs(i)) re++;
}
return re;
}
inline int del(int x)
{
RI int i,j;num=0;
for(i=1;i<=n;++i)
if(i!=x && (!g[0][x][i]) && (!g[0][i][x]))
res[++num]=i;
for(i=1;i<=num;++i)
for(j=1;j<=num;++j)
g[1][i][j]=g[0][res[i]][res[j]];
return num-maxmatch();
}
int main(){
RI int i,j,k,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
g[0][x][y]=1;
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
g[0][i][j]|=(g[0][i][k]&g[0][k][j]);
nw=0;num=n;
ans=n-maxmatch();
printf("%d\n",ans);
for(i=1;i<=n;++i) if(bel[i]) in[bel[i]]=1;
memset(used,0,sizeof(int)*(n+3));
for(i=1;i<=n;++i) if(!in[i]) dfs(i);
for(i=1;i<=n;++i) in[i]^=1;
for(i=1;i<=n;++i) in[bel[i]]=used[i];
for(i=1;i<=n;++i){
if(in[i] && (!used[i]))
putchar('1');
else putchar('0');
}
puts("");nw=1;
for(i=1;i<=n;++i) putchar('0'+(del(i)==ans-1));
return 0;
}