[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]) //mistake2
			f[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;
}


posted @ 2015-02-01 14:35  wfwbz  阅读(147)  评论(0编辑  收藏  举报