hdu3998 Sequence(最长上升子序列+最大流)

本文介绍了解决HDU 3998问题的方法,该问题是求解完全不同的最长上升子序列的个数。文章详细阐述了如何使用动态规划(DP)找到最长上升子序列,再利用最大流算法(Dinic和SAP实现)计算不同子序列的数量。通过代码示例,展示了两种最大流算法的具体实现和比较。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3998

【题意】求完全不同的最长上升子序列的个数。

【分析】dp求出最长上升子序列记为ans,然后使用最大流求解方案数。把每个点拆为两点X,Y。对于dp[i] == 1的点,连边(S,iX, inf),对于dp[i] == ans的点,连边(iY,T,inf);

(iX,iY,1)限制每个点只选一次。对于dp[j] + 1 == dp[i], j < i &&a[j] < a[i],连边(jY,iX,inf)。

 

跑dinic() 15ms

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<math.h>
  4 #include<algorithm>
  5 #include<vector>
  6 
  7 using namespace std;
  8 
  9 const int maxn = 1011;
 10 const int maxm = 1000010;
 11 const int inf = 100000000;
 12 
 13 int n;
 14 int a[maxn];
 15 int dp[maxn];
 16 int ans;
 17 
 18 
 19 struct Dinic{
 20     int node, src, dest, ne;
 21     int head[maxn], work[maxn], dist[maxn],Q[maxn];
 22     int flow[maxm], pnt[maxm], nxt[maxm];
 23     void init(int _node, int _src, int _dest)
 24     {
 25         node = _node;
 26         src = _src;
 27         dest = _dest;
 28         for (int i=0;i<node;i++)
 29         {
 30             head[i] = -1;
 31         }
 32         ne = 0;
 33     }
 34     void add(int u,int v, int c1,int c2)
 35     {
 36         pnt[ne] = v, flow[ne] = c1, nxt[ne] = head[u], head[u] = ne++;
 37         pnt[ne] = u, flow[ne] = c2, nxt[ne] = head[v], head[v] = ne++;
 38 
 39     }
 40     bool dinic_bfs(void)
 41     {
 42         int i,u,v,l,r=0;
 43         for(int i=0;i<node;i++)    dist[i]=-1;
 44         dist[Q[r++]=src]=0;
 45         for(l=0;l<r;l++)    for(i=head[u=Q[l]];i>=0;i=nxt[i])
 46             if(flow[i] && dist[v=pnt[i]]<0)
 47             {
 48                 dist[Q[r++]=v]=dist[u]+1;
 49                 if(v==dest)    return 1;
 50             }
 51         return 0;
 52     }
 53     int dinic_dfs(int u,int exp)
 54     {
 55         if(u==dest)    return exp;
 56         for(int &i=work[u],v,tmp;i>=0;i=nxt[i])
 57             if(flow[i] && dist[v=pnt[i]]==dist[u]+1 && (tmp=dinic_dfs(v,min(exp,flow[i])))>0)
 58             {
 59                 flow[i]-=tmp;
 60                 flow[i^1]+=tmp;
 61                 return tmp;
 62             }
 63         return 0;
 64     }
 65     int dinic_flow(void)
 66     {
 67         int i,res=0,delta;
 68         while(dinic_bfs())
 69         {
 70             for(i=0;i<node;i++)    work[i]=head[i];
 71             while(delta=dinic_dfs(src,inf))    res+=delta;
 72         }
 73         return res;
 74     }
 75 }Flow;
 76 
 77 int solve()
 78 {
 79     int s = 0, t = 2*n + 1, nn =2*n + 2;
 80     Flow.init(nn, s, t);
 81     for (int i=1;i<=n;i++)
 82     {
 83         Flow.add(i, i+n, 1, 0);
 84         if (dp[i] == ans){
 85             Flow.add(i+n, t,inf,0);
 86         }
 87         if (dp[i]==1){
 88             Flow.add(s, i, inf, 0);
 89             continue;
 90         }
 91         for (int j=i-1;j>=1;j--){
 92             if (dp[j]+1 == dp[i] && a[j] < a[i]){
 93                 Flow.add(j+n, i, inf, 0);
 94             }
 95         }
 96     }
 97     return Flow.dinic_flow();
 98 }
 99 int main()
100 {
101     while (scanf("%d",&n)==1)
102     {
103         for (int i=1;i<=n;i++)
104         {
105             scanf("%d",&a[i]);
106         }
107         memset(dp, 0, sizeof(dp));
108         ans = 1;
109         for (int i=1;i<=n;i++)
110         {
111             dp[i] = 1;
112             for (int j =1;j<i;j++)
113                 if (a[j] < a[i]){
114                     dp[i] = max(dp[i], dp[j] + 1);
115                 }
116             ans =  max(ans, dp[i]);
117         }
118         printf("%d\n%d\n",ans,solve());
119 
120 
121     }
122     return 0;
123 }
hdu3998

 

sap()  0 ms

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<math.h>
  4 #include<algorithm>
  5 #include<vector>
  6 
  7 using namespace std;
  8 
  9 const int maxn = 1011;
 10 const int maxm = 1000010;
 11 const int inf = 100000000;
 12 
 13 int n;
 14 int a[maxn];
 15 int dp[maxn];
 16 int ans;
 17 
 18 
 19 
 20 struct SAP{
 21     struct Edge{
 22     int v, next;
 23     int w;
 24     }edge[maxm];
 25     int head[maxn];
 26 
 27     int cnt;
 28     int n, s, t;//n = t + 1;
 29 
 30 
 31     int pre[maxn],cur[maxn],dis[maxn],gap[maxn];
 32 
 33     void add(int u,int v,int w)
 34     {
 35         edge[cnt].v=v;
 36         edge[cnt].w=w;
 37         edge[cnt].next=head[u];
 38         head[u]=cnt++;
 39         edge[cnt].v=u;
 40         edge[cnt].w=0;
 41         edge[cnt].next=head[v];
 42         head[v]=cnt++;
 43     }
 44 
 45     int sap()
 46     {
 47         int flow=0,aug=inf;
 48         int u;
 49         bool flag;
 50         for(int i=0;i<=n;i++)
 51         {
 52             cur[i]=head[i];
 53             gap[i]=dis[i]=0;
 54         }
 55         gap[s]=n;
 56         u=pre[s]=s;
 57         while(dis[s]<n)
 58         {
 59             flag=0;
 60             for(int &j=cur[u];j!=-1;j=edge[j].next)
 61             {
 62                 int v=edge[j].v;
 63                 if(edge[j].w>0&&dis[u]==dis[v]+1)
 64                 {
 65                     flag=1;
 66                     if(edge[j].w<aug) aug=edge[j].w;
 67                     pre[v]=u;
 68                     u=v;
 69                     if(u==t)
 70                     {
 71                         flow+=aug;
 72                         while(u!=s)
 73                         {
 74                             u=pre[u];
 75                             edge[cur[u]].w-=aug;
 76                             edge[cur[u]^1].w+=aug;
 77                         }
 78                         aug=inf;
 79                     }
 80                     break;
 81                 }
 82             }
 83             if(flag)
 84                 continue;
 85             int mindis=n;
 86             for(int j=head[u];j!=-1;j=edge[j].next)
 87             {
 88                 int v=edge[j].v;
 89                 if(edge[j].w>0&&dis[v]<mindis)
 90                 {
 91                   mindis=dis[v];
 92                   cur[u]=j;
 93                 }
 94             }
 95             if((--gap[dis[u]])==0)
 96                 break;
 97             gap[dis[u]=mindis+1]++;
 98             u=pre[u];
 99         }
100 
101         return flow;
102 
103     }
104 
105     void init(int __n,int __s, int __t)
106     {
107         n = __n;
108         s = __s;
109         t = __t;
110         cnt = 0;
111         memset(head,-1,sizeof(head));
112     }
113 }Flow;
114 
115 int solve()
116 {
117     int nn = 2*n + 2, s = 0, t = 2*n + 1;
118     Flow.init(nn,s,t);
119     for (int i=1;i<=n;i++)
120     {
121         Flow.add(i,i+n,1);
122         if (dp[i] == ans){
123             Flow.add(i+n,t,inf);
124         }
125         if (dp[i]==1){
126             Flow.add(s,i, inf);
127             continue;
128         }
129         for (int j=1;j<i;j++)
130             if (a[j] < a[i] && dp[j]+1 == dp[i]){
131                 Flow.add(j+n, i, inf);
132             }
133     }
134     return Flow.sap();
135 }
136 int main()
137 {
138     while (scanf("%d",&n)==1)
139     {
140         for (int i=1;i<=n;i++)
141         {
142             scanf("%d",&a[i]);
143         }
144         memset(dp, 0, sizeof(dp));
145         ans = 1;
146         for (int i=1;i<=n;i++)
147         {
148             dp[i] = 1;
149             for (int j =1;j<i;j++)
150                 if (a[j] < a[i]){
151                     dp[i] = max(dp[i], dp[j] + 1);
152                 }
153             ans =  max(ans, dp[i]);
154         }
155         printf("%d\n%d\n",ans,solve());
156     }
157     return 0;
158 }
hdu3998

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3710854.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值