https://loj.ac/problem/6005
根据以i开始最长的上升子序列分层,每一层连向下一层当且仅当a[i]<=a[j] 且dp[i]=dp[j]+1 这样保证网络流中每一个流量是1的走的都是最长的上升子序列,这样最大流就是答案
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;
const int maxn = 509;
int dp[maxn];
int a[maxn];
int s;
int n;
int head[maxn*3];
int tot = 0;
struct edge{
int v,nex,w;
}e[maxn*maxn*2];
void addedge(int u,int v,int w){
e[tot] = (edge){v,head[u],w};
head[u] = tot++;
e[tot] = (edge){u,head[v],0};
head[v] = tot++;
}
int deep[maxn*3];
bool bfs(int S,int T){
memset(deep,0,sizeof(deep));
deep[S] = 1;
queue<int> q;
q.push(S);
while (!q.empty()) {
int now = q.front();
q.pop();
for(int i=head[now];i!=-1;i=e[i].nex){
int v = e[i].v;
int w = e[i].w;
if(deep[v]!=0 || w<=0 ) continue;
deep[v] = deep[now]+1;
q.push(v);
}
}
return deep[T];
}
int dfs(int now,int T,int maxflow){
if(now==T) return maxflow;
int all = 0;
for(int i=head[now];i!=-1 && all <maxflow;i=e[i].nex){
int w = e[i].w;
int v = e[i].v;
if(deep[v]!=deep[now]+1 || w<=0) continue;
int tt = dfs(v,T,min(maxflow-all,w));
e[i].w-=tt;
e[i^1].w+=tt;
all+=tt;
}
return all;
}
int dinic(int S,int T){
int ret = 0;
while (bfs(S,T)) {
ret+=dfs(S,T,0x3f3f3f3f);
}
return ret;
}
void solve1(){
memset(head,-1,sizeof(head));
tot = 0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i]<=a[j]&& dp[i]==dp[j]+1){
addedge(2*i+1,2*j,1);
}
}
}
for(int i=1;i<=n;i++){
addedge(2*i,2*i+1,1);
if(dp[i]==s)
addedge(0, 2*i, 1);
if(dp[i]==1)
addedge(2*i+1, 1,1);
}
int ans = dinic(0,1);
if(s==1)
ans= n;
printf("%d\n",ans);
}
void solve2(){
memset(head,-1,sizeof(head));
tot = 0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(a[i]<=a[j]&& dp[i]==dp[j]+1){
addedge(2*i+1,2*j,1);
}
}
}
for(int i=1;i<=n;i++){
addedge(2*i,2*i+1,0x3f3f3f3f);
if(dp[i]==s)
addedge(0, 2*i, 0x3f3f3f3f);
if(dp[i]==1)
addedge(2*i+1, 1,0x3f3f3f3f);
}
int ans = dinic(0,1);
if(s==1)
ans = n;
printf("%d\n",ans);
}
int main(int argc, const char * argv[]) {
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
s = 0;
for(int i=n;i>=1;i--){
int t = 0;
for(int j=i+1;j<=n;j++){
if(a[i]<=a[j]){
t = max(t,dp[j]);
}
}
dp[i] = t+1;
s = max(dp[i],s);
}
printf("%d\n",s);
solve1();
solve2();
return 0;
}