先通过dp求出LIS假设为m,也就是经典的LIS问题。就求出了以点i为终点的LIS,即d[i];
然后题目要求输出所有点都不重合的LIS的方案。可以通过最大流来求解。可以想到一个从s到t的流对应于一种方案 。LIS的终点很显然只能是d值为m的点,所以在模型中只把 d值为m的点向终点t连一条有向边。任何一个LIS的起点一定是d值为1的点 所以s向d值为1的点连一条有向边。然后对于每一个点i,把j<i且的d[j]+1=d[i ],从j想i连一条边, 这样每一条从s出发的路都是一个上升子序列,如果到达终点是t则是一个最长上升子序列,然后 因为点都只能用一次,所以设定点的容量为1,这样得到的模型一个流就是最终结果的一种方案,因为流肯定只会沿着s到t的通路走。其余的边的容量只要大于等于点的容量都可以。
#include <iostream> #include <algorithm> #include <queue> using namespace std; const int maxn=2050; const int maxe=1000000; const int inf=1<<20; int a[maxn],g[maxn],d[maxn]; int n,s,t,tot; struct Edge { int from,to,next; int flow,cap; }; Edge e[maxe]; int head[maxn],dis[maxn],cur[maxn]; int lis() { for(int i=1;i<=n;i++) g[i]=inf; for(int i=1;i<=n;i++) { int k=lower_bound(g+1,g+n+1,a[i])-g; d[i]=k; g[k]=a[i]; } int result=-1; for(int i=1;i<=n;i++) result=max(result,d[i]); return result; } void addedge(int from,int to,int cap) { e[tot].from=from;e[tot].to=to;e[tot].flow=0;e[tot].cap=cap; e[tot].next=head[from];head[from]=tot;tot++; e[tot].from=to;e[tot].to=from;e[tot].flow=0;e[tot].cap=0; e[tot].next=head[to];head[to]=tot;tot++; } bool bfs() { memset(dis,-1,sizeof(dis)); queue<int > q; d[s]=0; q.push(s); while(!q.empty()) { int x=q.front();q.pop(); for(int i=head[x];i!=-1;i=e[i].next) { if(dis[e[i].to]==-1&&e[i].cap>e[i].flow) { dis[e[i].to]=dis[x]+1; q.push(e[i].to); } } } if(dis[t]==-1) return false; else return true; } int dfs(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int& i=cur[x];i!=-1;i=e[i].next) { if(dis[e[i].to]==(dis[x]+1)&&(f=dfs(e[i].to,min(a,e[i].cap-e[i].flow)))>0) { flow+=f; e[i].flow+=f; e[i^1].flow-=f; a-=f; if(a==0) break; } } return flow; } int maxflow() { int flow=0; while(bfs()) { memcpy(cur,head,(t+1)*sizeof(int)); flow+=dfs(s,inf); } return flow; } int main() { while(cin>>n) { memset(head,-1,sizeof(head)); s=0;t=2*n+1;tot=0; int i,j; for(i=1;i<=n;i++) scanf("%d",&a[i]); int limit=lis(); for(i=1;i<=n;i++) { addedge(i*2-1,i*2,1); if(d[i]==1) addedge(s,i*2-1,1); if(d[i]==limit) addedge(i*2,t,1); for(j=i-1;j>=1;j--) { if(d[j]+1==d[i]&&a[i]>a[j]) addedge(j*2,i*2-1,1); } } printf("%d\n",limit); printf("%d\n",maxflow()); } return 0; }