AOJ - WILDCARD

$O(n^2)$ $dp$로 문제를 해결한다.

문자열 $S,\,T$가 있을 때,

$\quad dp_{i,\,j}=S \text{ 와 } T$가 앞에서부터 $S_i$ 와 $T_j$ 까지 따졌을 때 매칭이 될 수 있는지 여부라고 하자.

$S_i=T_j$ 이거나 $S_{i}=$ ? 라면 $dp_{i,j}$ 는 $dp_{i-1,\,j-1}$ 이 참이라면 참이다.

만약 $S_i=$ * 이라면 $T_j$를 하나 없애거나 넘기지 않거나 선택지가 생기고,

  • 하나 없앨 때 $dp_{i,\,j-1}$
  • 없애지 않고 넘길 때 $dp_{i-1,\,j}$

둘 중 참이 하나라도 있으면 참이다.

가장 처음에 $dp_{0,\,0}$ 같은 경우는 1이고 만약 $S$의 가장 앞에 *가 붙어있는 경우 $dp_{1,\,j}$ 들이 모두 참이므로 잘 처리해주고 시작한다.

void solve() {  
   string a;  
   cin >> a;  
   int n;  
   cin >> n;  
   vs arr(n);  
   fv(arr);  
   a = " " + a;  
   vs ans;  
   for (string b: arr) {  
      n = sz(a) - 1;  
      int m = sz(b);  
      vvi dp(n + 1, vi(m + 1));  
      b = " " + b;  
      dp[0][0] = 1;  
  
      if (a[1] == '*') {  
         for (int j = 0; j <= m; j++)dp[1][j] = 1;  
      }  
  
      for (int i = 1; i <= n; i++) {  
         for (int j = 1; j <= m; j++) {  
            if (a[i] == b[j] || a[i] == '?') {  
               // 2, 1  
               // 1, 0               dp[i][j] |= dp[i - 1][j - 1];  
            }  
  
            if (a[i] == '*') {  
               dp[i][j] |= dp[i][j - 1] | dp[i - 1][j];  
            }  
         }  
      }  
      if (dp[n][m]) ans.pb(b.substr(1));  
   }  
   sort(all(ans));  
   for (string b: ans) cout << b << endl;  
}

Comments