生活随笔
收集整理的這篇文章主要介紹了
[codevs 1906] 最长递增子序列问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1906 最長遞增子序列問題
題解:
第一問是普通的DP,同時為后面做鋪墊。
后面的在《線性規劃與網絡流24題》里說的要比我好,引用來:
第一問動態規劃已經求出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>i且A[i] < A[j]且F[j]+1=F[i],從<i.b>到<j.a>連接一條容量為1的有向邊。
求網絡最大流,就是第二問的結果。把邊(<1.a>,<1.b>)(<N.a>,<N.b>)(S,<1.a>)(<N.b>,T)這四條邊的容量修改為無窮大,再求一次網絡最大流,就是第三問結果。
另外本題還有費用流的做法,但應該不會比2ms還快吧(求噴)。
代碼:
總時間耗費: 2ms?
總內存耗費: 364B
#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;const int maxn = 2000 + 10;
const int INF = 1e9 + 7;int n, m, s, t;
int a[maxn], f[maxn];struct Edge {int from, to, cap, flow;
};vector<Edge> edges;
vector<int> G[maxn];void AddEdge(int from, int to, int cap) {edges.push_back((Edge){from, to, cap, 0});edges.push_back((Edge){to, from, 0, 0});int sz = edges.size();G[from].push_back(sz-2);G[to].push_back(sz-1);
}bool vis[maxn];
int d[maxn];
bool BFS() {queue<int> Q;Q.push(s);memset(vis, 0, sizeof(vis));d[s] = 0;vis[s] = 1;while(!Q.empty()) {int u = Q.front(); Q.pop();for(int i = 0; i < G[u].size(); i++) {Edge& e = edges[G[u][i]];if(!vis[e.to] && e.cap > e.flow) {vis[e.to] = 1;d[e.to] = d[u] + 1;Q.push(e.to);}}}return vis[t];
}int cur[maxn];int DFS(int u, int a) {if(a == 0 || u == t) return a;int f, flow = 0;for(int& i = cur[u]; i < G[u].size(); i++) {Edge& e = edges[G[u][i]];if(d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {flow += f;e.flow += f;a -= f;edges[G[u][i]^1].flow -= f;if(a == 0) break;}}return flow;
}void Maxflow() {if(m == 1) { cout << n << endl; return; }int flow = 0;while(BFS()) {memset(cur, 0, sizeof(cur));flow += DFS(s, INF);}cout << flow << endl;
}void init() {cin >> n;for(int i = 1; i <= n; i++) cin >> a[i];s = 0; t = n * 2 + 1;
}void DP() {f[n] = 1;for(int i = n; i >= 1; i--) {f[i] = 1;for(int j = n; j > i; j--) if(a[i] <= a[j]) //mistake2f[i] = max(f[i], f[j]+1);m = max(m, f[i]);}cout << m << endl;
}void init_1() {for(int i = n; i >= 1; i--) {AddEdge(i, i+n, 1);if(f[i] == m) AddEdge(s, i, 1);if(f[i] == 1) AddEdge(i+n, t, 1);for(int j = i+1; j <= n; j++)if(f[i] == f[j] + 1 && a[i] <= a[j]) AddEdge(i+n, j, 1); //mistake3}
}void init_2() {edges.clear();for(int i = s; i <= t; i++) G[i].clear();for(int i = n; i >= 1; i--) {int cap = (i == 1 || i == n) ? INF : 1;AddEdge(i, i+n, cap); if(f[i] == m) AddEdge(s, i, cap); if(f[i] == 1) AddEdge(i+n, t, cap); for(int j = n; j > i; j--)if(f[i] == f[j] + 1 && a[i] <= a[j]) AddEdge(i+n, j, 1); //mistake4}
}int main() {init();DP();init_1();Maxflow();init_2();Maxflow();return 0;
}
總結
以上是生活随笔為你收集整理的[codevs 1906] 最长递增子序列问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。