[网络流24题]最长递增子序列问题
2017-10-11 08:30
411 查看
最长递增子序列问题
题目描述:
给定正整数序列x1,...,xn 。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
设计有效算法完成(1)(2)(3)提出的计算任务。
输入格式:
第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。
输出格式:
第1 行是最长递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
输入样例#1:
4
3 6 2 5
输出样例#1:
2
2
3
题解:
(1).用dp解决就可以了,f[i]为以i为终点最长子序列的长度,再简单不过了。
(2).网络流解决吧,首先根据题意“取出”可知每个数只能选一次那么就直接想到拆点了(后面讲不拆点的方法)连边分四种情况:①若f[i]=1将i和s连一条容量为1的边。②若f[i]=s,将i+n和t连一条容量为1的边。③若f[i]=f[j]+1 && w[i]<w[j] 将j+n和i连一条容量为1的边。④将i和i+n连边
(3).第三问还比较好做,既然不限制使用次数,将容量设成inf就可以了。
还有拆点是必须拆的,因为出现重复选择的情况(但是没拆点的代码竟然过了?可能数据太水了吧)。例如:
5
8 1 9 11 10
建图如图
:
代码:
题目描述:
给定正整数序列x1,...,xn 。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
设计有效算法完成(1)(2)(3)提出的计算任务。
输入格式:
第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。
输出格式:
第1 行是最长递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
输入样例#1:
4
3 6 2 5
输出样例#1:
2
2
3
题解:
(1).用dp解决就可以了,f[i]为以i为终点最长子序列的长度,再简单不过了。
(2).网络流解决吧,首先根据题意“取出”可知每个数只能选一次那么就直接想到拆点了(后面讲不拆点的方法)连边分四种情况:①若f[i]=1将i和s连一条容量为1的边。②若f[i]=s,将i+n和t连一条容量为1的边。③若f[i]=f[j]+1 && w[i]<w[j] 将j+n和i连一条容量为1的边。④将i和i+n连边
(3).第三问还比较好做,既然不限制使用次数,将容量设成inf就可以了。
还有拆点是必须拆的,因为出现重复选择的情况(但是没拆点的代码竟然过了?可能数据太水了吧)。例如:
5
8 1 9 11 10
建图如图
:
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; const int max_m = 3000001; const int max_n = 3001; int f[max_n],w[max_n]; int point[max_n],nxt[max_m],v[max_m],remain[max_m]; int deep[max_n],cur[max_n]; int n,x,y,tot,s,t,inf,maxn,ans; inline void clear() { memset(point,-1,sizeof(point)); memset(nxt,-1,sizeof(nxt)); for(int i=1; i<=n; ++i) f[i]=1; tot=-1; inf=1e9; s=0; maxn=1; t=2*n+1; f =1; } inline void addedge(int x,int y,int cal) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cal; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; } inline int dfs(int now,int t,int limit) { if(now==t || !limit) return limit; int flow=0,f; for(int i=cur[now]; i!=-1; i=nxt[i]) if(deep[v[i]]==deep[now]+1 && (f=dfs(v[i],t,min(remain[i],limit)))) { flow+=f; limit-=f; remain[i]-=f; remain[i^1]+=f; if(!limit) break; } return flow; } inline bool bfs(int s,int t) { memset(deep,0x7f,sizeof(deep)); for(int i=s; i<=t; ++i) cur[i]=point[i]; queue<int> q; deep[s]=0; q.push(s); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=point[now]; i!=-1; i=nxt[i]) if(deep[v[i]]>inf && remain[i]) { deep[v[i]]=deep[now]+1; q.push(v[i]); } } return deep[t]<inf; } inline int dinic(int s,int t) { int ans=0; while(bfs(s,t)) ans+=dfs(s,t,inf); return ans; } int main() { scanf("%d",&n); clear(); for(int i=1; i<=n; ++i) scanf("%d",&w[i]); for(int i=1; i<=n; ++i)//dp求最长递增子序列 for(int j=1; j<i; ++j) if(w[j]<=w[i]) { f[i]=max(f[j]+1,f[i]); maxn=max(maxn,f[i]); } printf("%d\n",maxn); for(int i=1; i<=n; ++i) addedge(i,i+n,1); for(int i=1; i<=n; ++i) { if(f[i]==1) addedge(s,i,1); if(f[i]==maxn) addedge(i+n,t,1); } for(int i=1; i<=n; ++i) for(int j=1; j<i; ++j) if(w[j]<=w[i] && f[i]==f[j]+1) addedge(j+n,i,1); printf("%d\n",ans=dinic(s,t)); addedge(s,1,inf);//将1和n容量设为inf addedge(1,1+n,inf); if(f ==maxn) { addedge(2*n,t,inf); addedge(n,2*n,inf); } printf("%d\n",dinic(s,t)+ans); return 0; }
相关文章推荐
- code vs [网络流24题] 最长递增子序列问题
- 【codevs1906】[网络流24题]最长递增子序列问题
- [网络流24题]最长递增子序列问题
- 【网络流24题】最长递增子序列问题
- 网络流24题 最长递增子序列问题
- 最长递增子序列问题[网络流24题之6]
- [网络流24题] 最长递增子序列问题 最大流/
- [网络流24题]最长递增子序列问题 最大流
- COGS731 [网络流24题] 最长递增子序列(最大流)
- 网络流24题之六 最长递增子序列
- 网络流24题之T6 最长递增子序列问题
- [网络流24题]最长上升子序列问题
- 网络流 6最长递增子序列问题
- ★ 最长递增子序列问题 (最多不相交路径)(分层思想) 网络流最大流
- 网络流24题:最长递增子序列问题
- [网络流24题] 06 最长递增子序列(最多不相交路径,最大流)
- 网络流 6最长递增子序列问题
- kyeremal-网络流24题T6-最长递增子序列问题
- 【线性规划与网络流24题 6】最长递增子序列
- Libre 6005 「网络流 24 题」最长递增子序列 / Luogu 2766 最长递增子序列问题(网络流,最大流)