您的位置:首页 > 理论基础 > 计算机网络

网络流二十四题之六 —— 最长不下降子序列问题(ALIS)

2016-05-12 13:32 543 查看

最长不下降子序列问题

Description

给定正整数序列 x1,…,xn 。

(1)计算其最长不下降子序列的长度 s。

(2)计算从给定的序列中最多可取出多少个长度为 s 的不下降子序列。

(3)如果允许在取出的序列中多次使用 x1 和 xn,则从给定序列中最多可取出多少个长

度为 s 的不下降子序列。

Input

文件第 1 行有 1 个正整数 n,表示给定序列的长度。

接下来的 1 行有 n 个正整数 x1,…,xn 。

Output

程序运行结束时,将任务(1)(2)(3)的解答输出。

第 1 行是最长不下降子序列的长度 s。

第 2 行是可取出的长度为 s 的不下降子序列个数。

第 3 行是允许在取出的序列中多次使用 x1 和 xn 时可取出的长度为 s 的不下降子序列个数。

Sample Input

4

3 6 2 5

Sample Output

2

2

3

Solution

第一问用动态规划。因为数据规模不大,O(n2) 可以过。

第二问用网络流。

若存在 j>i,并且 fj=fi+1(fi 表示以 i 为结束的最长不下降子序列的长度),那么将 i 与 j 连一条边。

连接 i 与 s,当 fi=1。

连接 i 与 t,当 fi=ans1。

求最大流即可。

第三问,将第一个点和最后一个点连的边的权值设为 ∞ 即可。

Code

[cpp] #include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define ss 0
#define tt 900
#define INF 0x3f3f3f3f

using namespace std;

int n,ans1,cnt;
int s[1000];
int f[1000];
int head[1000];
int nxt[1000010];
int data[1000010];
int flow[1000010];
int dis[1000];
queue<int>q;

void add(int x,int y,int z){
nxt[cnt]=head[x];data[cnt]=y;flow[cnt]=z;head[x]=cnt++;
nxt[cnt]=head[y];data[cnt]=x;flow[cnt]=0;head[y]=cnt++;
}

bool BFS(){
memset(dis,-1,sizeof dis);
dis[ss]=0;
q.push(ss);
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=head[now];i!=-1;i=nxt[i]){
if(flow[i]&&dis[data[i]]==-1){
q.push(data[i]);
dis[data[i]]=dis[now]+1;
}
}
}
return dis[tt]>0;
}

int dfs(int now,int low){
if(now==tt)return low;
int Low;
for(int i=head[now];i!=-1;i=nxt[i]){
if(flow[i]&&dis[data[i]]==dis[now]+1){
if(Low=dfs(data[i],Min(low,flow[i]))){
flow[i]-=Low;
flow[i^1]+=Low;
return Low;
}
}
}
return 0;
}

int main(){
freopen(”alis.in”,“r”,stdin);
freopen(”alis.out”,“w”,stdout);
scanf(”%d”,&n);
memset(head,-1,sizeof head);
for(int i=1;i<=n;i++)scanf(“%d”,&s[i]);
f[1]=1;
for(int i=2;i<=n;i++){
f[i]=1;
for(int j=1;j<i;j++)
if(s[i]>=s[j])f[i]=Max(f[i],f[j]+1);
ans1=Max(ans1,f[i]);
}
printf(”%d\n”,ans1);
for(int i=1;i<=n;i++){
if(f[i]==1)add(ss,i,1);
if(f[i]==ans1)add(i,tt,1);
for(int j=i+1;j<=n;j++)
if(f[j]==f[i]+1&&s[j]>=s[i])add(i,j,1);
}
int flag,ans2=0;
while(BFS())
while(flag=dfs(ss,INF))ans2+=flag;
printf(”%d\n”,ans2);
if(ans1==1){
printf(”%d\n”,ans2);
return 0;
}
cnt=0;
memset(head,-1,sizeof head);
memset(data,0,sizeof data);
memset(nxt,0,sizeof nxt);
memset(flow,0,sizeof flow);
for(int i=1;i<=n;i++){
if(f[i]==1){
if(i!=1&&i!=n)
add(ss,i,1);
else add(ss,i,INF);
}
if(f[i]==ans1){
if(i!=1&&i!=n)
add(i,tt,1);
else add(i,tt,INF);
}
for(int j=i+1;j<=n;j++)
if(f[j]==f[i]+1&&s[j]>=s[i]){
if(ans1==2&&i==1&&j==n){
add(i,j,1);
continue;
}
if(i==1||i==n||j==1||j==n)
add(i,j,INF);
else add(i,j,1);
}
}
int ans3=0;
while(BFS())
while(flag=dfs(ss,INF))ans3+=flag;
printf(”%d\n”,ans3);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: