【网络流24题】最长不下降子序列问题 题解

题目传送门

题目大意: 三个问:1、最长不下降子序列长度(设为 k k k),2、每个元素只能用一次,最多能取出多少个长度为 k k k 的不下降子序列,3、第 1 1 1 个和第 n n n 个元素可以重复使用,其它与第 2 2 2 问一样。

题解

第一问但凡有点 d p dp dp 基础都能做吧qwq

第二问的话直接建图,设 f [ i ] f[i] f[i] 表示以第 i i i 个元素结尾的最长不下降子序列长度,那么让所有 f [ i ] = 1 f[i]=1 f[i]=1 的和源点连边, f [ i ] = f m a x f[i]=f_{max} f[i]=fmax 的和汇点连边,满足 a i ≤ a j a_i\leq a_j aiaj f [ j ] = f [ i ] + 1 f[j]=f[i]+1 f[j]=f[i]+1 的, i i i j j j 连边。流量都是 1 1 1,为了限制每个元素只能用 1 1 1 次,我们把每个点拆开,中间连 1 1 1 条流量为 1 1 1 的边即可,跑最大流就是答案。

第三问的话加几条边,源点向 1 1 1 连, 1 1 1 的分身之间连, f [ n ] f[n] f[n] 如果等于 f m a x f_{max} fmax 那么 n n n 与汇点连, n n n 的分身之间连,这些边流量无限。然后在第二问跑完的图的基础上继续跑即可,答案要加上第二问的答案。(当然,重新建图再跑也行)

以及,当第一问答案为 1 1 1 时,剩下两个问的答案就是 n n n,别忘了这个特判。

代码如下:

#include 
#include 
#include 
using namespace std;
#define maxn 2010
#define inf 999999999

int n,a[maxn],f[maxn],max_f=0,tou,wei;
struct edge{int y,z,next;};
edge e[300010];
int first[maxn],len=1;
void buildroad(int x,int y,int z)
{
	e[++len]=(edge){y,z,first[x]};
	first[x]=len;
}
int h[maxn],q[maxn],st,ed;
bool bfs()
{
	memset(h,0,sizeof(h));
	st=ed=1;q[st]=tou;h[tou]=1;
	while(st<=ed)
	{
		int x=q[st++];
		for(int i=first[x];i;i=e[i].next)
		if(h[e[i].y]==0&&e[i].z>0)h[e[i].y]=h[x]+1,q[++ed]=e[i].y;
	}
	return h[wei]>0;
}
int dfs(int x,int flow)
{
	if(x==wei)return flow;
	int tt=0;
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(h[y]==h[x]+1&&e[i].z>0&&flow-tt>0)
		{
			int p=dfs(y,min(e[i].z,flow-tt));tt+=p;
			e[i].z-=p;e[(i^1)].z+=p;
		}
	}
	if(!tt)h[x]=0; return tt;
}
void work()
{
	for(int i=1;i<=n;i++)
	{
		if(f[i]==1)buildroad(tou,i,1),buildroad(i,tou,0);
		if(f[i]==max_f)buildroad(i+n,wei,1),buildroad(wei,i+n,0);
	}
	for(int i=1;i<n;i++)
	for(int j=i+1;j<=n;j++)
	if(a[i]<=a[j]&&f[i]+1==f[j])buildroad(i+n,j,1),buildroad(j,i+n,0);
	for(int i=1;i<=n;i++)buildroad(i,i+n,1),buildroad(i+n,i,0);
	
	int ans=0;
	while(bfs())ans+=dfs(tou,inf);
	printf("%d\n",ans);
	
	buildroad(tou,1,inf);buildroad(1,tou,0);
	buildroad(1,1+n,inf);buildroad(1+n,1,0);
	if(f[n]==max_f)buildroad(n+n,wei,inf),buildroad(wei,n+n,0);
	buildroad(n,n+n,inf);buildroad(n+n,n,0);
	
	while(bfs())ans+=dfs(tou,inf);
	printf("%d\n",ans);
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	for(int j=0;j<i;j++)
	if(a[j]<=a[i])f[i]=max(f[i],f[j]+1),max_f=max(max_f,f[i]);
	printf("%d\n",max_f);
	if(max_f==1)return printf("%d\n%d\n",n,n),0;
	tou=2*n+1;wei=tou+1;
	work();
}

你可能感兴趣的:(网络流24题)