参考链接:
http://www.cnblogs.com/gentleh/archive/2013/03/30/2989958.html

题意:求一个序列的最长上升子序列,及其个数(注意:两个最长上升子序列不能共有同一个数,才能算两个)

思路:用dp+最大流来求,首先用两次循环dp求出最长上升子序列的长度ans,然后就是建图了,可以选择源点为0,
由于数列中的每一个数只能使用一次,构图的时候需要拆点。若有n个数,则拆成2 * n个点,构造源点s=0和汇点t=2*n+1,
将每个点(i)都和自己拆出来的点(i+n)连边,将源点和dp[i]=1的点连边,将dp[i]=ans的点与汇点连边,
最后若dp[j] = dp[i] + 1,则将i + n和 j连边。所有边的流量都是1,这样便可以限制每个点只使用一次。
其实连边的顺序就是最长序列为1,2,3,...,ans。可以理解为从最长序列为1(该数本身)一直流到数列中的最长上升序列。

这里要注意的是,由于数据弱,有不用拆点也能A的。但是为了保证每个点都是用一次,一定要拆点。
如果不拆点的话,可以见下图,则中间那个点可能会被用两次,具体不仔细说了。

我一开始按照dinic模板打了一遍,结果TLE。。。后来经别人指点,加了dinic中的两个判断条件,见(1)和(2),瞬间A了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <queue>
#define INF 0x3f3f3f3f using namespace std;
const int maxn=;
int n,m;
int a[maxn]; //序列
int pri[maxn*];
int head[maxn*]; //因为要拆点
int s,t; //s:源点 t:汇点
int dp[maxn];
int tot=;
int ans,num;//最长上升子序列的长度,以及不同的个数。 struct Edge{
int from,to;
int next;
int c,f;
}edge[maxn*]; void add(int x,int y,int val){
edge[tot].next=head[x];
edge[tot].from=x;
edge[tot].to=y;
edge[tot].c=val; //注意这里是c为val,反向边c为0
//edge[tot].f=0;
head[x]=tot++; edge[tot].next=head[y];
edge[tot].from=y;
edge[tot].to=x;
edge[tot].c=;
//edge[tot].f=0;
head[y]=tot++;
}
bool BFS(){
queue<int>q;
memset(pri,-,sizeof(pri));
pri[]=;//源点
q.push();
while(!q.empty()){
int tmp=q.front();
q.pop();
for(int k=head[tmp];k!=-;k=edge[k].next){
int v=edge[k].to;
if(pri[v]==- && edge[k].c>){
pri[v]=pri[tmp]+;
if(v==t){
return true;
}
q.push(v);
}
}
}
return false;
} int dinic(int p,int flow){
if(p==t){
return flow;
}
int f=flow;
for(int k=head[p];k!=-;k=edge[k].next){
int v=edge[k].to;
if(pri[v]==pri[p]+ && edge[k].c>){
int a=edge[k].c; //a为该边可以增加的流量
int ff=dinic(v,min(a,flow)); //ff为路径中所有a的最小值,即为该条路中可以增加的流量
//edge[k].f+=ff;
//edge[k^1].f-=ff; //因为双向边是同时建的,编号必定一奇一偶成对的,如0、1;2、3;4、5;
//这样用k异或1即可求得对应的反向边
edge[k].c-=ff;
edge[k^].c+=ff;
flow-=ff;
if(flow<=)
break; //(1)
}
}
if(f-flow<=)
pri[p]=-; //(2)
//如果从p点流出去的流量<=0,那么设置pri[p]的值为-1,之后在dinic中就不考虑到p点的情况了。
return f-flow;
} int main()
{
while(scanf("%d",&n)!=EOF){
for(int i=;i<=n;i++){
dp[i]=;
scanf("%d",&a[i]);
}
for(int i=;i<=n;i++){
for(int j=;j<i;j++){
if(a[i]>a[j] && dp[j]+>dp[i])
dp[i]=dp[j]+;
}
}
m=*n+;
ans=;
for(int i=;i<=n;i++){
ans=max(dp[i],ans);
}
memset(head,-,sizeof(head));
tot=; s=;
t=*n+;
for(int i=;i<=n;i++){
add(i,i+n,);
if(dp[i]==)
add(s,i,);
if(dp[i]==ans)
add(i+n,t,);
}
for(int i=;i<=n;i++){
//下面j只要从i+1开始即可,因为add加边是加双向边的
for(int j=i+;j<=n;j++){
if(dp[j]==dp[i]+){
add(i+n,j,);
}
}
}
num=;
while(BFS()){
num+=dinic(s,INF);
}
printf("%d\n%d\n",ans,num); }
return ;
}

HDU 3998 Sequence (最长上升子序列+最大流)的更多相关文章

  1. HDU 3998 Sequence(经典问题,最长上升子序列)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3998 解题报告:求一个数列的最长上升子序列,并求像这样长的不相交的子序列最多有多少个. 我用的是最简单 ...

  2. hdu 5748(求解最长上升子序列的两种O(nlogn)姿势)

    Bellovin Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total Submission(s): Accepte ...

  3. HDU 4681 String 最长公共子序列

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4681 题意: 给你a,b,c三个串,构造一个d串使得d是a,b的子序列,并且c是d的连续子串.求d最大 ...

  4. HDU 1159.Common Subsequence-最长公共子序列(LCS)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  5. hdu 3998 Sequence

    There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequence of X as x[i1], ...

  6. hdu 1025 dp 最长上升子序列

    //Accepted 4372 KB 140 ms //dp 最长上升子序列 nlogn #include <cstdio> #include <cstring> #inclu ...

  7. hdu 5489(LIS最长上升子序列)

    题意:一个含有n个元素的数组,删去k个连续数后,最长上升子序列        /*思路参考GoZy 思路: 4 2 3 [5 7 8] 9 11 ,括号表示要删掉的数, 所以  最长上升子序列  = ...

  8. hdu 5532(最长上升子序列)

    Input The first line contains an integer T indicating the total number of test cases. Each test case ...

  9. Cogs 731. [网络流24题] 最长递增子序列(最大流)

    [网络流24题] 最长递增子序列 ★★★☆ 输入文件:alis.in 输出文件:alis.out 简单对比 时间限制:1 s 内存限制:128 MB «问题描述: 给定正整数序列x1,-, xn. ( ...

随机推荐

  1. 安装SQL Server Management Studio遇到的29506错误

    首先要在IIS里把internet 信息哪项选上.然后在安装SQL Server, 在安装的时候一直报 29506错误,装了几次,不知道什么原因.谷歌了一下说是权限的问题. 很纳闷,我当然用的是管理员 ...

  2. ThinkPHP 3.2.2跨控制器调用方法

     所谓跨控制器调用,指的是在一个控制器中调用另一个控制器的某个方法.在ThinkPHP中有三种方式实现跨控制器调用: 直接实例化: A()函数实例化; R()函数实例化. (1)直接实例化  直接实例 ...

  3. malloc calloc realloc,new区别联系以及什么时候用

    三个函数的申明分别是:void* realloc(void* ptr, unsigned newsize);void* malloc(unsigned size);void* calloc(size_ ...

  4. hdu 4715 Difference Between Primes

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4715 Difference Between Primes Description All you kn ...

  5. android开发系列之由ContentValues看到的

    这本篇博客里面我想重点来分析一下ContentValues的源码以及它里面涉及到的继承接口Parcelabel,还有HashMap的源码. 相信使用过android里面数据库操作的朋友对于Conten ...

  6. 如何快速重置OUTLOOK2013,2016到初始配置状态,outlook 修改数据文件位置

    适用范围: 安装OUTLOOK的机器 知识点分析: 快速清除当前OUTLOOK所有账户,回归到初始配置状态. 操作步骤: WIN+R调出运行 输入: C:\Program Files (x86)\Mi ...

  7. mvc中使用knockoutjs和ajax

    虽然说knockoutjs 官网上写的非常的清楚!但是像我这样的英语呕吐患者,真是虐心啊!今天我写下做个记录,也为那些初次使用的同学给予帮助, 首先我说一下今天我说的内容只是应用不做原理探究,如果没有 ...

  8. How to insert a character into a NSString

    How do I insert a space to a NSString. I need to add a space at index 5 into: NString * dir = @" ...

  9. android apk 自我保护技术-加密apk

    经过了忙碌的一周终于有时间静下来写点东西了,我们继续介绍android apk防止反编译技术的另一种方法.前两篇我们讲了加壳技术(http://my.oschina.net/u/2323218/blo ...

  10. 华为HG8240光猫-破解-联通-2016-telnet-http

    序 我与大家想法基本一致,拿到联通的光猫后,心想它应该是个路由器吧,如果让它自己拨号上网就好了,即省一台路由器,又省电了.抱着这个想法,在2013年里,我搜罗了不少文章,经过Q群,搜索,询问,阅读,理 ...