1. 程式人生 > >南陽理工學院動態規劃專題 括號問題2 總結

南陽理工學院動態規劃專題 括號問題2 總結

南陽理工學院動態規劃專題括號問題2總結

這道題目初看起來很簡單,但是我從看題到思考,到做題ac足足花了一個晚上加一個下午的時間,我也有到網上找程式碼的習慣,但是都是遞迴,特別蛋疼,我想用正統的動歸去做,於是就開始了不一樣的艱難探索之旅。

分析過程:

使用char str[1001]這個字元陣列儲存最初輸入的括號序列,使用dp[1001][1001]這個陣列儲存中間結果,dp[i][j]的意思是從下標為i的字元到下標為j的字元的子問題最少要加多少個括號才能規範化。首先dp陣列初始化為零,顯然dp[i][i]=1;至於dp[i][i+1],str[i][i+1]配對的時候=0,當str[i][i+1]不配對的時候=2

;到了這一步初始化工作結束。

如果str[i]str[j]配對則分為兩種情況:

1.      i->(…)(…)<-j,dp[i][j]=min{dp[i][k]+dp[k+1][j]};

2.      i->(..(..)..)<-j,dp[i][j]=dp[i+1][j-1],因為之前dp[i+1][j-1]已經計算過,因此直接使用即可。

如果str[i]str[j]不配對分為四種情況:

1.  str[i+1]str[j]的字串當中有與str[i]配對的括號,其對應的下標序列為k1,k2,k3,…

dp[i][j]=min{dp[i][k1]+dp[k1+1][j], dp[i][k2]+dp[k2+1][j],dp[i][k3]+dp[k3+1][j],…};

2.  當不存在與str[i]相匹配的括號時直接使用dp[i][j]=dp[i+1][j]+1;

3.  str[i]str[j-1]的字串當中有與str[j]配對的括號,其對應的下標序列為k1,k2,k3,…

dp[i][j]=min{dp[i][k1-1]+dp[k1][j], dp[i][k2-1]+dp[k2][j],dp[i][k3-1]+dp[k3][j],…};

4.  不存在與str[i]相匹配的括號時直接使用dp[i][j]=dp[i][j-1]+1;

計算完成後dp[0][strlen(str)-1]即是計算結果。

Ac程式碼:

#include<iostream>

#include<stdio.h>

#include<string.h>

#define INF 100000000

using namespace std;

char str[101];

int dp[101][101];

bool match(char ch1,char ch2)

{

   if(ch1=='('&&ch2==')')return true;

   if(ch1=='['&&ch2==']')return true;

   return false;

}

int main()

{

   int cas;

   cin>>cas;

   while(cas--)

    {

      int top=-1;

      memset(str,0,sizeof(str));

      cin>>str;

     int l1=strlen(str);

     if(l1==0)

     {

         cout<<"0"<<endl;

         continue;

     }

     for(int i=0;i<l1;i++)dp[i][i]=1;

     for(int i=0;i<l1-1;i++)

     {

         if(match(str[i],str[i+1]))

         {

              dp[i][i+1]=0;

         }

         else{dp[i][i+1]=2;}

     }

         for(int k=2;k<l1;k++)

         {

           for(int i=0;i+k<l1;i++)

           {

              int j=i+k;

              if(match(str[i],str[j]))

              {

                 int min1=INF;

                 for(int kk=i+1;kk<j;kk++)

                 {

                     intt=dp[i][kk]+dp[kk+1][j];

                     if(min1>t)

                        min1=t;

                 }

                 int min2=dp[i+1][j-1];

                 dp[i][j]=min(min1,min2);

              }

              else

              {

                  int min1=INF;

                  for(int kk=i+1;kk<j;kk++)

                  {

                      if(match(str[i],str[kk]))//檢查左端

                      {

                          intt=dp[i][kk]+dp[kk+1][j];

                          if(min1>t)

                             min1=t;

                      }

                  }

                  int min2=dp[i+1][j]+1;

                  int min3=IN

                  for(intkk=i+1;kk<j;kk++)//檢查右端

                  {

                      if(match(str[kk],str[j]))

                      {

                          intt=dp[i][kk-1]+dp[kk][j];

                          if(min3>t)

                            min1=t;

                      }

                  }

                  int min4=dp[i][j-1]+1;

                 dp[i][j]=min(min(min1,min2),min(min3,min4));

              }

         }

     }

     cout<<dp[0][l1-1]<<endl;

//     for(int i=0;i<l1;i++)

//     {

//         for(int j=0;j<l1;j++)

//         {

//              cout<<dp[i][j]<<' ';

//         }

//         cout<<endl;

//     }

 

    }

}

括號匹配(二)

時間限制:1000 ms  | 記憶體限制:65535 KB

難度:6

描述

給你一個字串,裡面只包含"(",")","[","]"四種符號,請問你需要至少新增多少個括號才能使這些括號匹配起來。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的

輸入

第一行輸入一個正整數N,表示測試資料組數(N<=10)
每組測試資料都只有一行,是一個字串S,S中只包含以上所說的四種字元,S的長度不超過100

輸出

對於每組測試資料都輸出一個正整數,表示最少需要新增的括號的數量。每組測試輸出佔一行

樣例輸入

4

[]

([])[]

((]

([)]

樣例輸出

0

0

3

2

來源

上傳者

張雲聰