[swust 1741] 最长递增子序列问题(DP,最大流)

题目链接:https://www.oj.swust.edu.cn/problem/show/1741

此题同上,但是多一个问:x1和xn能用多次。

解法一样,只不过这两个点相关的边都是inf就行了。这样可以表示能无限用。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3
  4 typedef struct Edge {
  5     int u, v, w, next;
  6 }Edge;
  7
  8 const int inf = 0x7f7f7f7f;
  9 const int maxn = 6660;
 10
 11 int cnt, dhead[maxn];
 12 int cur[maxn], dd[maxn];
 13 Edge dedge[maxn<<8];
 14 int S, T, N;
 15
 16 void init() {
 17     memset(dhead, -1, sizeof(dhead));
 18     for(int i = 0; i < maxn; i++) dedge[i].next = -1;
 19     S = 0; cnt = 0;
 20 }
 21
 22 void adde(int u, int v, int w, int c1=0) {
 23     dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w;
 24     dedge[cnt].next = dhead[u]; dhead[u] = cnt++;
 25     dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1;
 26     dedge[cnt].next = dhead[v]; dhead[v] = cnt++;
 27 }
 28
 29 bool bfs(int s, int t, int n) {
 30     queue<int> q;
 31     for(int i = 0; i < n; i++) dd[i] = inf;
 32     dd[s] = 0;
 33     q.push(s);
 34     while(!q.empty()) {
 35         int u = q.front(); q.pop();
 36         for(int i = dhead[u]; ~i; i = dedge[i].next) {
 37             if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) {
 38                 dd[dedge[i].v] = dd[u] + 1;
 39                 if(dedge[i].v == t) return 1;
 40                 q.push(dedge[i].v);
 41             }
 42         }
 43     }
 44     return 0;
 45 }
 46
 47 int dinic(int s, int t, int n) {
 48     int st[maxn], top;
 49     int u;
 50     int flow = 0;
 51     while(bfs(s, t, n)) {
 52         for(int i = 0; i < n; i++) cur[i] = dhead[i];
 53         u = s; top = 0;
 54         while(cur[s] != -1) {
 55             if(u == t) {
 56                 int tp = inf;
 57                 for(int i = top - 1; i >= 0; i--) {
 58                     tp = min(tp, dedge[st[i]].w);
 59                 }
 60                 flow += tp;
 61                 for(int i = top - 1; i >= 0; i--) {
 62                     dedge[st[i]].w -= tp;
 63                     dedge[st[i] ^ 1].w += tp;
 64                     if(dedge[st[i]].w == 0) top = i;
 65                 }
 66                 u = dedge[st[top]].u;
 67             }
 68             else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) {
 69                 st[top++] = cur[u];
 70                 u = dedge[cur[u]].v;
 71             }
 72             else {
 73                 while(u != s && cur[u] == -1) {
 74                     u = dedge[st[--top]].u;
 75                 }
 76                 cur[u] = dedge[cur[u]].next;
 77             }
 78         }
 79     }
 80     return flow;
 81 }
 82
 83 int n;
 84 int x[maxn];
 85 int dp[maxn];
 86 int ret;
 87
 88 void work1() {
 89     ret = 0;
 90     memset(dp, 0, sizeof(dp));
 91     for(int i = 1; i <= n; i++) {
 92         dp[i] = 1;
 93         for(int j = 1; j <= i; j++) {
 94             if(x[i] > x[j]) dp[i] = max(dp[i], dp[j]+1);
 95         }
 96         ret = max(ret, dp[i]);
 97     }
 98     printf("%d\n", ret);
 99 }
100
101 void work2() {
102     if(ret == 1) {
103         printf("%d\n", n);
104         return;
105     }
106     init();
107     S = 0, T = 2 * n + 1, N = T + 1;
108     for(int i = 1; i <= n; i++) {
109         adde(i, i+n, 1);
110         if(dp[i] == 1) adde(S, i, 1);
111         if(dp[i] == ret) adde(i+n, T, 1);
112     }
113     for(int i = 2; i <= n; i++) {
114         for(int j = 1; j < i; j++) {
115             if(x[i] > x[j] && dp[i] == dp[j] + 1) {
116                 adde(j+n, i, 1);
117             }
118         }
119     }
120     cout << dinic(S, T, N) << endl;
121 }
122
123 void work3() {
124     if(ret == 1) {
125         printf("%d\n", n);
126         return;
127     }
128     init();
129     S = 0, T = 2 * n + 1, N = T + 1;
130     for(int i = 1; i <= n; i++) {
131         if(i == 1 || i == n) {
132             adde(i, i+n, inf);
133             if(dp[i] == 1) adde(S, i, inf);
134             if(dp[i] == ret) adde(i+n, T, inf);
135         }
136         else {
137             adde(i, i+n, 1);
138             if(dp[i] == 1) adde(S, i, 1);
139             if(dp[i] == ret) adde(i+n, T, 1);
140         }
141     }
142     for(int i = 2; i <= n; i++) {
143         for(int j = 1; j < i; j++) {
144             if(x[i] > x[j] && dp[i] == dp[j] + 1) {
145                 adde(j+n, i, 1);
146             }
147         }
148     }
149     cout << dinic(S, T, N) << endl;
150 }
151
152 int main() {
153     // freopen("in", "r", stdin);
154     while(~scanf("%d",&n)) {
155         init();
156         for(int i = 1; i <= n; i++) scanf("%d", &x[i]);
157         work1(); work2();
158     }
159     return 0;
160 }
时间: 2024-10-10 13:14:46

[swust 1741] 最长递增子序列问题(DP,最大流)的相关文章

[luoguP2766] 最长递增子序列问题(最大流)

传送门 题解来自网络流24题: [问题分析] 第一问时LIS,动态规划求解,第二问和第三问用网络最大流解决. [建模方法] 首先动态规划求出F[i],表示以第i位为开头的最长上升序列的长度,求出最长上升序列长度K. 1.把序列每位i拆成两个点<i.a>和<i.b>,从<i.a>到<i.b>连接一条容量为1的有向边. 2.建立附加源S和汇T,如果序列第i位有F[i]=K,从S到<i.a>连接一条容量为1的有向边. 3.如果F[i]=1,从<i

[cogs731] [网络流24题#6] 最长递增子序列 [网络流,最大流]

[转hzwer]第一问是LIS,动态规划求解,第二问和第三问用网络最大流解决.首先动态规划求出F[i],表示以第i位为开头的最长上升序列的长度,求出最长上升序列长度K.1.把序列每位i拆成两个点<i.a>和<i.b>,从<i.a>到<i.b>连接一条容量为1的有向边.2.建立附加源S和汇T,如果序列第i位有F[i]=K,从S到<i.a>连接一条容量为1的有向边.3.如果F[i]=1,从<i.b>到T连接一条容量为1的有向边.4.如果j

动态规划(DP),最长递增子序列(LIS)

题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(dp[k])+1,(k<i),(a[k]<a[i]) #include <stdio.h> #define MAX 1005 int a[MAX];///存数据 int dp[MAX];///dp[i]表示以a[i]为结尾的最长递增子序列(LIS)的长度 int main() { int

Redraiment的走法(最长递增子序列问题的求解--dp问题)

输入描述: 输入多行,先输入数组的个数,再输入相应个数的整数 输出描述: 输出结果 输入例子: 6 2 5 1 5 4 5 输出例子: 3 提示 Example: 6个点的高度各为 2 5 1 5 4 5 如从第1格开始走,最多为3步, 2 4 5 从第2格开始走,最多只有1步,5 而从第3格开始走最多有3步,1 4 5 从第5格开始走最多有2步,4 5 所以这个结果是3. //最长递增子序列问题--动态规划问题 1 import java.util.*; 2 public class Test

Bridging signals POJ 1631(最长递增子序列dp)

原题 题目链接 题目分析 由题目知,如果能求出连接点的最长递增子序列,则可以把连接不在该序列中的点的线全部剪掉.而维护最长递增子序列可以用dp来做,考虑到相同长度的递增子序列末尾数字越小越好,可以这样定义dp,dp[i]长度为i的递增子序列的最小末尾值,初始化为INF,由于这个dp具有有序性,因此可以用二分来加快更新,每次遍历到值num[i],只需二分找出大于等于num[i]的更新之即可.最后从扫一遍dp数组即可得到最长长度. 代码 1 #include <iostream> 2 #inclu

POJ 2533 Longest Ordered Subsequence【最长递增子序列】【DP思想】

Longest Ordered Subsequence Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total Submission(s) : 6   Accepted Submission(s) : 1 Problem Description A numeric sequence of ai is ordered ifa1 < a2 < ... < aN. Let t

HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典

Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1666    Accepted Submission(s): 614 Problem Description There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequ

[网络流24题]最长递增子序列问题

题目大意:给定长度为n的序列a,求:1.最长递增子序列长度:2.最多选出几个不相交的最长递增子序列:3.最多选出几种在除了第1个和第n个以外的地方不相交的最长递增子序列.(n<=1000) 思路:先倒着DP,求出f[i]表示以a[i]开头的最长的递增子序列长度,然后建图,若f[i]=最长递增子序列长度则S向i连1,若f[i]=1则i向T连1,若i<j且a[i]<a[j]且f[i]=f[j]+1则i向j连1,为保证每个点只被流一次,拆成入点和出点,流量限制1,跑最大流即可解决第二问,点1和

hdu1087最长递增子序列

原题地址 简单dp题,LIS.不同之处是这里要求得的不是最长的子序列,而是权重和最长的子序列.其实大同小异. 状态数组就是到达每个位置的最大权重. LIS问题常用解法就是两个: 人人为我 我为人人 本题我用了我为人人的思路 .就是确定子序列起点,把其后面每一个大于它的值的位置的状态数组更新. #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using name