mini notes

競技プログラミングの解法メモを残していきます。

DPまとめコンテスト G - Longest Path

G - Longest Path

概要

N頂点M辺のDAGの最長パスの長さを出力せよ。

制約

2 \leq N \leq 10^5
1 \leq M \leq 10^5

方針①

まず、トポロジカルソートを行い、頂点の移動順を求める。
トポロジカルソートは帰りがけ順DFSの出力の逆順とする。

次に、dp[i] : トポロジカルソートで頂点iより後ろのパスの最大長 とし、DPする。
これは、トポロジカルソートされた頂点を逆順で見てゆき、頂点iに対して、その頂点が出発点となる各辺の行先点jについて、dp[j]が最も大きいものに1を足して更新してゆけばよい。

解答①

Submission #3959327 - Educational DP Contest / DP まとめコンテスト

#include <bits/stdc++.h>
 
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define rep(i,n) FOR(i,0,n)
#define RFOR(i,a,b) for(int i=(a)-1;i>=(b);i--)
#define rrep(i,n) RFOR(i,n,0)
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
 
// トポロジカルソート
int n, m;
const int max_n = 1e5 + 10;
 
vector<int> g[max_n];
bool used[max_n];
 
vector<int> v;
 
void dfs(int u){
	if(used[u]) return;
	used[u] = true;
	for(int i: g[u]) dfs(i);
	//帰りがけ順で追加
	v.push_back(u);
}
 
void tsort(){
	for(int i = 0; i < n; i++) dfs(i);
	reverse(v.begin(), v.end());
}
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	cin >> n >> m;
	rep(i, m){
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		g[x].push_back(y);
	}
 
	tsort();
	reverse(v.begin(), v.end());
 
	// cout << "tsort--";
	// rep(i, n) cout << " " << v[i];
	// cout << endl;
 
	// dp[i] : トポロジカルソートで頂点iより後ろのパスの最大長
	vector<int> dp(n, 0);
	int ans = 0;
	for(int i: v){
		for(int u : g[i]){
			// cout << i << " " << u << " " << dp[i] << " " << (dp[u]+1) << endl;
			dp[i] = max(dp[i], dp[u] + 1);
		}
		ans = max(ans, dp[i]);
	}
 
	cout << ans << endl;
}

方針②

上記更新をメモ化再帰で行う。(実はトポロジカルソートは必要ない)

解答②

Submission #3959330 - Educational DP Contest / DP まとめコンテスト

#include <bits/stdc++.h>
 
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define rep(i,n) FOR(i,0,n)
#define RFOR(i,a,b) for(int i=(a)-1;i>=(b);i--)
#define rrep(i,n) RFOR(i,n,0)
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
 
const int max_n = 1e5 + 10;
int n, m;
vector<int> g[max_n];
int d[max_n];
 
int dfs(int x){
	if(d[x] > 0) return d[x];
	int mx = 0;
	rep(i, g[x].size()){
		mx = max(mx, dfs(g[x][i]) + 1);
	}
 
	d[x] = mx;
	return mx;
}
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	cin >> n >> m;
	rep(i, m){
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		g[x].push_back(y);
	}
 
	rep(i, n) d[i] = 0;
 
	int ans = 0;
	rep(i, n){
		if(d[i] == 0) ans = max(ans, dfs(i));
	}
 
	cout << ans << endl;
}