1. 程式人生 > >#動態規劃,最大流#洛谷 2766 最長不下降子序列問題

#動態規劃,最大流#洛谷 2766 最長不下降子序列問題

題目

求序列的最長不下降子序列的長度及最長不下降序列的個數
還有求若第一個數和最後一個數可以取無限次,那麼會有多少個最長不下降序列

分析

第一問動態規劃Fi=max{Fj+1}
第二問按照方向建邊拆點跑最大流,第三問修改無限大。

程式碼

#include <cstdio>
#include <cctype>
#include <queue>
#define max(a,b) (a>b?a:b)
using namespace std;
struct node{int y,w,next;}e[50001];
int
n,a[501],dp[501],s,t,dis[1003],ans1,ans,k=1,ls[1003]; int in(){ int ans=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=ans*10+c-48,c=getchar(); return ans; } void add(int x,int y,int w){e[++k]=(node){y,w,ls[x]}; ls[x]=k; e[++k]=(node){x,0,ls[y]}; ls[y]=k;} bool bfs(int
s){ for (int i=1;i<=t;i++) dis[i]=0; queue<int>q; q.push(s); dis[s]=1; while (q.size()){ int x=q.front(); q.pop(); for (int i=ls[x];i;i=e[i].next) if (e[i].w>0&&!dis[e[i].y]){ dis[e[i].y]=dis[x]+1; if (e[i].y==t) return 1
; q.push(e[i].y); } } return 0; } int dinic(int x,int now){ if (x==t||!now) return now; int rest=0,f; for (int i=ls[x];i;i=e[i].next) if (e[i].w>0&&dis[e[i].y]==dis[x]+1){ rest+=(f=dinic(e[i].y,min(now-rest,e[i].w))); e[i].w-=f; e[i^1].w+=f; if (now==rest) return rest; } if (!rest) dis[x]=0; return rest; } void update(int x,int ny,int y){ for (int i=ls[x];i;i=e[i].next){ if (e[i].y==ny) e[i^1].w=1e4; if (e[i].y==y) e[i].w=1e4; } } int main(){ n=in(); s=n<<1|1,t=s+1; for (int i=1;i<=n;i++) a[i]=in(),dp[i]=1; for (int i=2;i<=n;i++) for (int j=1;j<i;j++) if (a[j]<=a[i]) dp[i]=max(dp[i],dp[j]+1);//動態規劃 for (int i=1;i<=n;i++) ans=max(ans,dp[i]); printf("%d\n",ans);//求最大值 for (int i=1;i<=n;i++){ add(i,i+n,1); // if (dp[i]==1) add(s,i,1); //如果可開始不下降序列 if (dp[i]==ans) add(i+n,t,1);//如果找到終點 } for (int i=2;i<=n;i++) for (int j=1;j<i;j++) if (a[j]<=a[i]&&dp[i]==dp[j]+1) add(j+n,i,1);//建邊 while (bfs(s)) ans1+=dinic(s,1e6); printf("%d\n",ans1);//跑最大流 update(1,s,1+n); if (dp[n]==ans) update(n<<1,n,t); while (bfs(s)) ans1+=dinic(s,1e6); return !printf("%d",ans1); }