题目链接

最长不下降子序列问题

解题思路

分成三小问解决。

第一小问,求\(LIS\),因为\(n<=500\),直接\(O(N^2)\)暴力求解即可。

第二三小问,建立模型用网络流求解。

对于第二小问

\((1)\)首先,因为每个点只能使用一次,考虑拆点,把每一个点拆成\(i,n+i\)两个点,从\(i\)连向\(n+i\)一条长度为\(1\)的有向边。

\((2)\)其次,因为流向是从S经集合E到T,其中任意集合E中元素\(i\)需要满足的条件是\(i\)位于LIS上,故:

①出边从\(lis[i]=k\)的点流向T

②所有的能构成E的边都需要加入,也就是任意\(i,j\)满足\(i<j,a[i]<a[j],lis[i]=lis[j]-1\)都从\(i\)到\(j\)连边。

跑一遍最大流即可。

第三小问唯一的不同就是\(S\)流向\(1\),\(1\)流向\(1+n\),\(n\)流向\(n+n\),\(n+n\)流向\(T\)四条路长度变成\(inf\)而已,改后再跑一遍最大流即可。

AC代码

#include<stdio.h>
#include<string.h>
int lis[1020],a[1020],len;//lis
int s,t,inf=0x3fffffff;//ek
struct Edge{
int end,length,near;
}edge[50020];
int head[1020],cnt=2,vis[1020];
void addedge(int begin,int end,int length){
edge[cnt].end=end;
edge[cnt].length=length;
edge[cnt].near=head[begin];
head[begin]=cnt;
cnt++;
}
struct Pre{
int pre,ednum;
}pre[1020];
int bfs(){
memset(vis,0,sizeof(vis));
int queue[50010]={0},headq=0,tail=0,i;
queue[tail++]=s;
vis[s]=1;
while(headq<tail){
int v=queue[headq];
for(i=head[v];i;i=edge[i].near){
int p=edge[i].end;
if(vis[p]||!edge[i].length)continue;
vis[p]=1;
pre[p].pre=v;
pre[p].ednum=i;
queue[tail++]=p;
if(p==t)return 1;
}
headq++;
}
return 0;
}
int ek(){
int min,ans=0,i;
while(bfs()){
min=inf;
for(i=t;i!=s;i=pre[i].pre){
int en=pre[i].ednum;
if(min>edge[en].length)min=edge[en].length;
}
for(i=t;i!=s;i=pre[i].pre){
int en=pre[i].ednum;
edge[en].length-=min;
edge[en^1].length+=min;
}
ans+=min;
}
return ans;
}
int main(){
int i,j,n;
scanf("%d",&n);
s=2*n+3;
t=2*n+4;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
lis[i]=1;
}
//lis n<=500 O(N2)
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if(a[i]>=a[j]&&lis[i]<lis[j]+1)lis[i]=lis[j]+1;
for(i=1;i<=n;i++)if(lis[i]>len)len=lis[i];
printf("%d\n",len);
//ek1 建图求最大流
for(i=1;i<=n;i++){
addedge(i,i+n,1);//拆点
addedge(i+n,i,0);
if(lis[i]==1){
addedge(s,i,1);
addedge(i,s,0);
}
if(lis[i]==len){
addedge(i+n,t,1);
addedge(t,i+n,0);
}
}
for(i=1;i<=n;i++){
for(j=1;j<i;j++){
if(lis[i]==lis[j]+1&&a[i]>=a[j]){
addedge(j+n,i,1); addedge(i,j+n,0);
}
}
}
printf("%d\n",ek());
//ek2
memset(pre,0,sizeof(pre));
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
cnt=2;
for(i=1;i<=n;i++){
addedge(i,i+n,1);//拆点
addedge(i+n,i,0);
if(lis[i]==1){
addedge(s,i,1);
addedge(i,s,0);
}
if(lis[i]==len){
addedge(i+n,t,1);
addedge(t,i+n,0);
}
}
for(i=1;i<=n;i++){
for(j=1;j<i;j++){
if(lis[i]==lis[j]+1&&a[i]>=a[j]){
addedge(j+n,i,1); addedge(i,j+n,0);
}
}
}
addedge(1,1+n,inf); addedge(1+n,1,0);
addedge(s,1,inf); addedge(1,s,0);
if(lis[n]==len){
addedge(n,n+n,inf); addedge(n+n,n,0);
addedge(n+n,t,inf); addedge(t,n+n,0);
}
printf("%d\n",ek());
return 0;
}

最新文章

  1. 详解Python中的循环语句的用法
  2. DOCKER windows安装
  3. MAC系统下,删除.svn文件
  4. java 删除目录、 文件
  5. bootstrap的select2校验及不影响原来的格式
  6. GD库使用小结---1
  7. (poj)3159 Candies
  8. HibernateTemplate类的方法flush()
  9. go get 代理设置
  10. memcached配置
  11. 201521123099 《Java程序设计》第13周学习总结
  12. hdu-4635(tarjan缩点)
  13. 图像转化成TFrecords格式并回转
  14. 「客户成功故事」OneAPM 助力网上办事大厅构建阳光、高效、安全的政务服务平台
  15. sublime text3 插件的安装
  16. Linux 操作系统死机故障处理方法总结
  17. Spring配置动态数据源-读写分离和多数据源
  18. Maven介绍及安装与配置
  19. NS3 Ptr&lt;Rocket&gt; 与 TcpRocket 的一个小问题
  20. symfony学习笔记2—纯的PHP代码和symfony的区别

热门文章

  1. haut-1282 ykc想吃好吃的
  2. codeforces 5C
  3. redis跳表
  4. 洛谷p2216 多次单调队列,扫描矩阵中的最大值减去最小值最的固定大小子矩阵
  5. Taro 3.x in Action
  6. vue template
  7. OOP &amp; 模块化, 多态, 封装
  8. LeetCode 算法题解 js 版 (001 Two Sum)
  9. TypeScript &amp; global.d.ts
  10. [Python] 茎叶图和复合饼图的画法