感觉和传纸条很像,听说网络流能写
然而并不想写,还是选择了拓排加DP
考虑一下这题和传纸条DP的区别
边界N.M过大,2000,无法承受
O
(
N
2
∗
M
2
)
O(N^2*M^2)
O(N2∗M2)算法,甚至优化后的
O
(
N
∗
M
2
)
O(N*M^2)
O(N∗M2)的也不行
我们考虑改变DP顺序,因为这题的豆子是空间内的一些点,而且每次只能往上往右走,如果按照传纸条的方法DP,会求出非常多的无用量,如何避免呢,我们选择建图
对于一个豆子,我们向他右上方的可行点连一条单向边,然后进行拓扑排序,按拓扑序进行DP
但是极限情况下还是会产生4e6条边,我们考虑如何减少
很显热,如果三个点i,j,k,满足如图所示的位置关系,那么i,k之间肯定是不同连边的
因为
i
−
>
j
−
>
k
i->j->k
i−>j−>k肯定优于
i
−
>
k
i->k
i−>k的,好了,建边的问题解决了,那么如何DP呢
我们定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示P1吃到第
i
i
i个豆子,P2吃到第
j
j
j个豆子,获得的最大分数
为什么可以这么设定呢?
还是考虑上面三个豆子,
f
[
j
]
[
k
]
=
?
f[j][k]=?
f[j][k]=?显然有两种,一种是原来的,或者由
f
[
i
]
[
k
]
+
1
f[i][k]+1
f[i][k]+1转移而来
换成一般式就是
f
[
x
t
o
]
[
y
]
=
m
a
x
(
f
[
x
t
o
]
[
y
]
,
f
[
x
]
[
y
]
+
1
)
f[x_{to}][y]=max(f[x_{to}][y],f[x][y]+1)
f[xto][y]=max(f[xto][y],f[x][y]+1)
但是如果
x
t
o
x_{to}
xto和
y
y
y相等怎么办这时显然不能再更新了,因为不符合豆子只能吃一次的要求
所以这时方程式就是
f
[
x
t
o
]
[
y
]
=
m
a
x
(
f
[
x
t
o
]
[
y
]
,
f
[
x
]
[
y
]
)
f[x_{to}][y]=max(f[x_{to}][y],f[x][y])
f[xto][y]=max(f[xto][y],f[x][y])
主体结束,我们考虑一些细节,如何保证
x
t
o
x_{to}
xto一定可以转移到
y
y
y呢
别忘了,我们统计了拓扑序,如果
x
t
o
x_{to}
xto可以转移到
y
y
y,那么
r
d
[
y
]
>
r
d
[
x
t
o
]
rd[y]>rd[x_{to}]
rd[y]>rd[xto]是一定成立的,所以,
y
y
y的拓扑序一定在
x
t
o
x_{to}
xto后面,但如果出现了在前面的情况,我们
s
w
a
p
(
x
t
o
,
y
)
swap(x_{to},y)
swap(xto,y)一下就行
大概流程就是这样
上代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2007;
struct node{
int to,next;
}edge[maxn*maxn];
int cnt,head[maxn];
void add(int from,int to){
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
}
struct P{
int x,y;
friend bool operator <(P a,P b){
return a.x!=b.x?a.x<b.x:a.y<b.y;
}
}po[maxn];
int n,rd[maxn],st=0,ed,f[maxn][maxn];
int tot,id[maxn],th[maxn];
void toopsort(){
queue<int>q;q.push(0);
while(q.size()){
int f1=q.front();
q.pop();
id[f1]=++tot;
th[tot]=f1;
for(int i=head[f1];i;i=edge[i].next)
if(--rd[edge[i].to]==0)q.push(edge[i].to);
}
}
void dp(int x,int y){
for(int k=head[x];k;k=edge[k].next){
int from=edge[k].to,to=y;
if(id[from]>id[to])swap(from,to);
if(from==to)f[from][to]=max(f[from][to],f[x][y]);
else f[from][to]=max(f[from][to],f[x][y]+1);
}
}
int main()
{
scanf("%d",&n);ed=n+1;
for(int i=1;i<=n;++i)
scanf("%d%d",&po[i].x,&po[i].y);
sort(po+1,po+1+n);
for(int t,i=1;i<=n;i++)
for(int j=i+1,t=1e9;j<=n;j++)
if(po[i].y<=po[j].y&&po[j].y<t){
t=po[j].y;
rd[j]++;
add(i,j);
}
for(int i=1;i<=n;i++){
add(st,i),rd[i]++;
add(i,ed),rd[ed]++;
}
toopsort();
/*for(int i=1;i<=n;i++)cout<<th[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++)cout<<id[i]<<" ";
cout<<endl;*/
for(int i=1;i<=tot;i++){
for(int j=i;j<=tot;j++){
dp(th[i],th[j]);
}
}
cout<<f[ed][ed]-1<<endl;
return 0;
}