読者です 読者をやめる 読者になる 読者になる

Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

Typical DP Contest I - イウィ

問題文 : イウィ


Greedy でも解けるらしいが, ここはDP.

$check[x][y] :=$ 区間x, y を適切な順番で取り除くことですべてをiwiとして取り出せるか? とする.
あとは, 個数が最大になるように同じようにDP テーブルを更新していく. $O(N^3)$.

コード :

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cassert>
#include <vector>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <map>

using namespace std;

bool memo[333][333];
int dp[333][333];

int main()
{
	//memset(memo, -1, sizeof(memo));
	char s[1024];
	
	scanf("%s", s);
	int l = strlen(s);
	
	for (int i = 0; i < l; i++)
		for (int j = 0; j < i; j++)
			memo[i][j] = true;
	
	for (int d = 3; d <= l; d++){
		for (int i = 0; i <= l - d; i++){
			for (int j = i + 1; j < i + d - 1; j++){
				if (s[i] == 'i' && s[j] == 'w' && s[i + d - 1] == 'i' &&
					memo[i + 1][j - 1] && memo[j + 1][i + d - 2]) memo[i][i + d - 1] = true;
				if (memo[i][j] && memo[j + 1][i + d - 1]) memo[i][i + d - 1] = true;
			}
		}
	}
	
	for (int i = 0; i < l; i++)
		for (int j = i + 1; j < l; j++)
			if (memo[i][j]) dp[i][j] = (j - i + 1) / 3;
	
	for (int d = 3; d <= l; d++){
		for (int x = 0; x <= l - d; x++){
			dp[x][x + d] = max(dp[x][x + d], max(dp[x + 1][x + d], dp[x][x + d - 1]));
			for (int mid = x + 1; mid < x + d - 1; mid++){
				dp[x][x + d] = max(dp[x][x + d], dp[x][mid] + dp[mid + 1][x + d - 1]);
			}
		}
	}
	
	printf("%d\n", dp[0][l - 1]);
	
	return (0);
}