土下座しながら探索中

主に競技プログラミング

AOJ 2090 : Repeated Subsequences

問題リンク:Repeated Subsequences | Aizu Online Judge

問題概要:
長さが300以下の文字列があたえられる
この文字列を空でない2つの文字列に分ける
こうしてできる2つの文字列のLCSの中で最も長いものを出力せよ
複数ある場合はどれを出力しても良い

解法:
実際に300回文字列を分けてみて、それらのLCSを求め、そのなかの最長のものを出力する

実装時間:
21分

コード:

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define IINF (INT_MAX)

using namespace std;

int dx[] = {-1,-1,+0};
int dy[] = {-1,+0,-1};

string lcs(string A,string B){
  int lena = A.size();
  int lenb = B.size();
  int dp[lena+1][lenb+1],path[lena+1][lenb+1];
  for(int i=0;i<=lena;i++)for(int j=0;j<=lenb;j++)dp[i][j] = 0, path[i][j] = -1;

  for(int i=0;i<lena;i++){
    for(int j=0;j<lenb;j++){
      if(A[i] == B[j]){
	dp[i+1][j+1] = dp[i][j] + 1; 
	path[i+1][j+1] = 0;
      } else {
	if(dp[i+1][j] < dp[i][j+1]){
	  dp[i+1][j+1] = dp[i][j+1];
	  path[i+1][j+1] = 2;
	} else {
	  dp[i+1][j+1] = dp[i+1][j];
	  path[i+1][j+1] = 1;
	}
      }
    }
  }

  string ret = "";
  int x = lenb, y = lena;
  while(true){
    if(!( 0 <= x && x <= lenb && 0 <= y && y <= lena ))break;
    if(path[y][x] == -1)break;
    if(path[y][x] == 0){
      ret += A[y-1];
    }
    int dir = path[y][x];
    x += dx[dir], y += dy[dir];
  }
  reverse(ret.begin(),ret.end());
  return ret;
}

int main(){
  string line;
  while(cin >> line,line != "#END"){
    string ans = "";
    for(int i=0;i<line.size()-1;i++){
      string A = line.substr(0,i+1);
      string B = line.substr(i+1);
      string C = lcs(A,B);
      if( C.size() > ans.size() ){
	ans = C;
      }
    }
    cout << ans << endl;
  }
  return 0;
}