POJ #1141

A bottom-up DP. To be honest, it is not easy to relate DP to this problem. Maybe, all "most""least" problems can be solved using DP..

Reference: http://blog.sina.com.cn/s/blog_8e6023de01014ptz.html

There's an important details to AC: in case of "())", there are 2 solutions: ()() and (()). For the AC code, the former one is preferred.

//    1141
//    http://blog.sina.com.cn/s/blog_8e6023de01014ptz.html
//
#include <stdio.h>
#include <string.h>
#include <memory.h>

#define MAX_LEN 101 
 
 bool isMatched(char *in, int i, int j)
 {
     return (in[i] == '(' && in[j] == ')') || (in[i] == '[' && in[j] == ']');
 }
 void printPath(int path[MAX_LEN][MAX_LEN], int i, int j, char in[MAX_LEN])
{
     int sInx = path[i][j];
     if (sInx == -1)
     {
         if (i == j)
         {
             //printf("Complete @ %d
", i);
             switch (in[i])
             {
             case '(': 
             case ')': printf("()"); break;
             case '[': 
             case ']': printf("[]"); break;
             }
             return;
        }        
         else if (i + 1 == j)
         {
             //printf("Already matched: [%d, %d]
", i, j);
             printf("%c%c", in[i], in[j]);
             return;
         }
         else if ((i+1) < j)
         {
             printf("%c", in[i]);
             printPath(path, i + 1, j - 1, in);
             printf("%c", in[j]);
         }
     }
     else
     {
         printPath(path, 0, path[i][j], in);
         //printf("Break @ %d
", path[i][j], in);
         printPath(path, path[i][j] + 1, j, in);
     }
 }
 
 void calc(char in[MAX_LEN])
 {
     unsigned slen = strlen(in);
     if (slen == 0)
     {
         printf("
");
         return;
     }
     else if (slen > 0)
     {
         int dp[MAX_LEN][MAX_LEN];
         int path[MAX_LEN][MAX_LEN];
 
         //    Init
         for (int i = 0; i < MAX_LEN; i ++)
         for (int j = 0; j < MAX_LEN; j++)
         {
             dp[i][j] = 0xFFFFFF;
             path[i][j] = -1;
         }
 
         //    Def: dp[i][j] = min num of chars to add, from i to j
         //    Recurrence relation:
         //    1. dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]), where k in (i..j)
         //    2. dp[i][j] = dp[i+1][j-1], <IF in[i]:in[j] = [] or ()>
 
         //    i..j is range, k is interval
         for (int k = 0; k < slen; k++)    // NOTE: this is a bottom-up DP. We have to go from 0 to slen as interval
         for (int i = 0, j = i + k; i < slen - k; i ++, j ++)
         {
             if (i == j)
             {
                 dp[i][j] = 1;
                 path[i][j] = -1;
                 continue;
             }
             bool bIsMatched = isMatched(in, i, j);
             if (bIsMatched)        // eq 2
             {
                 if (k == 1)        // length == 2 
                 {
                     dp[i][j] = 0;    
                     path[i][j] = -1;
                     continue;
                 }
                 else if (k > 1)    // length > 2
                 {
                     dp[i][j] = dp[i + 1][j - 1];                                        
                     path[i][j] = -1;    // we don't split matched pair
                     //    A: we still go ahead with eq1
                 }                
             }
             //else    // eq1
             {
                 //    t is iterator of split index
                 for (int t = i; t < j; t++)
                 {
                     int newVal = dp[i][t] + dp[t + 1][j];
                     if (newVal <= dp[i][j]) // Label A: we prefer splitted solution
                     {
                         dp[i][j] = newVal;
                         path[i][j] = t;
                     }
                 }
             }
         }
         printPath(path, 0, slen - 1, in);
     } //    if (slen > 0)
 }
 
 int main()
{
     char in[MAX_LEN] = { 0 };
     gets(in);
     calc(in);
     printf("
");
     return 0;
}
View Code
原文地址:https://www.cnblogs.com/tonix/p/3806001.html