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; }