1. 程式人生 > >區間DP 入門經典三道題

區間DP 入門經典三道題

#include <cstdio>
#include <iostream>
#include <cstring>
#define sf scanf
#define pf printf

using namespace std;
typedef long long LL;
const int maxn = 205;
/*
    題意: N堆石子排成一排 每次可以合併相鄰的兩堆石子 合併的代價是兩堆石子的數量的和
            在經過N - 1次合併和,N堆石子合併為一堆石子,問最小的代價是多少
    DP[i][j] 表示將第i堆和第j堆合併為一堆的最小花費
    那麼DP[i][j] 就可以表示成 DP[i][j] = min{DP[i][k] + DP[k + 1][j] + COST((i ~ k):(k + 1 ~ j))}

*/
const LL INF = 0x3f3f3f3f; LL DP[maxn][maxn]; LL A[maxn]; LL DPS(int l,int r){ if(DP[l][r] != -1) return DP[l][r]; LL& ans = DP[l][r]; ans = INF; LL L = 0,R = 0; for(int i = l;i <= r;++i) R += A[i]; for(int k = l;k < r;++k){ L += A[k],R -= A[k]; ans = min(ans,L + R + DPS(l,k) + DPS(k + 1
,r)); } return ans; } int main(){ int n; while( ~sf("%d",&n) ){ for(int i = 0;i < n;++i) sf("%lld",A + i); memset(DP,-1,sizeof(DP)); for(int i = 0;i < n;++i) DP[i][i] = 0; DPS(0,n - 1); pf("%lld\n",DP[0][n - 1]); } return 0; }
#include <cstdio>
#include <iostream> #include <cstring> #define sf scanf #define pf printf using namespace std; /* 題意:給一個只包含‘[’,‘]’,‘(’,‘)’的字串求在這個字串的一個最長的子串 是一個合法括號字元 DP[i][j] 表示將i 到 j 變為合法字串要刪除的最少字元數 那麼 DP[i][j] = min{DP[i][k] + DP[k + 1][j]};check(s[i],s[j]) DP[i][j] = min(DP[i][j],DP[i + 1][j - 1]); */ const int INF = 0x3f3f3f3f; const int maxn = 105; int DP[maxn][maxn]; char s[maxn]; int DPS(int l,int r){ if(~DP[l][r]) return DP[l][r]; int& ans = DP[l][r]; ans = INF; if(s[l] == '(' && s[r] == ')' || s[l] == '[' && s[r] == ']') ans = min(ans,DPS(l + 1,r - 1)); for(int k = l;k < r;++k){ ans = min(ans,DPS(l,k) + DPS(k + 1,r)); } return ans; } int main(){ while(sf("%s",s)){ if(s[0] == 'e') break; int len = strlen(s); memset(DP,-1,sizeof(DP)); for(int i = 0;i < len;++i){ DP[i][i] = 1; DP[i + 1][i] = 0; } pf("%d\n",len - DPS(0,len - 1)); } return 0; }
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define sf scanf
#define pf printf
using namespace std;
typedef long long int LL;
/*  分類 區間DP入門題
    題意: 要求將一個整數N 劃分成M段 使這M段的乘積最大

    現在我們將整數 看作一個由數字組成的字串 那麼
    DP[l][r][m] 表示將子串(l - r)劃分成M段的最大乘積的值
    那麼DP[l][r][m] max{DP[l][k][p] * DP[k + 1][r][q]}  (k >= l ^ k < r ^ (p + q) == m)

*/

const int maxn = 20;
LL DP[maxn][maxn][maxn];
LL G[maxn],F[maxn];
int len;
char s[maxn];
LL DPS(int l,int r,int m){
    if(~DP[l][r][m]) return DP[l][r][m];
    LL& ans = DP[l][r][m] = 0;
    if(r - l + 1 < m) ans = 0;
    else if(m == 1){
        ans = G[l] / F[r + 1];
    }
    else for(int k = l;k < r;++k){
        for(int p = 1;p <= m;++p){
            for(int q = 1;q <= m;++q){
                if(p + q == m){
                    ans = max(ans,DPS(l,k,p) * DPS(k + 1,r,q));
                }
            }
        }
    }
//    pf("%d %d %d %lld\n",l,r,m,ans);
    return ans;
}


int main(){
    int T;sf("%d",&T);
    while( T-- ){
        memset(DP,-1,sizeof(DP));
        int n,m;
        sf("%s %d",s,&m);
        len = n = strlen(s);
        F[len] = 1;
        G[len] = 0;
        for(int i = len - 1;~i;--i) {
            F[i] = F[i + 1] * 10;
            G[i] = G[i + 1] + (s[i] - '0') * F[i + 1];
        }
//        pf("%lld\n",G[0] / F[1]);
        pf("%lld\n",DPS(0,n - 1,m));
    }
    return 0;
}

相關推薦

區間DP 入門經典

#include <cstdio> #include <iostream> #include <cstring> #define sf scanf #defi

【51nod 1021】石子歸併(區間dp入門

1021 石子歸併 基準時間限制:1 秒 空間限制:131072 KB 分值: 20 難度:3級演算法題 收藏 關注 N堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將N堆石子合併成一堆的最小代價。

[POJ-1651]Multiplication Puzzle [區間DP 入門]

The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes on

聯想面試智力,聽說前面必考(有部份解答)

                聯想面試智力題,所說前面三道題必考,這個沒有被證實過。不過,當用來完完了沒有什麼不可的。    題目如下:    1、一條繩子,從一頭點燃,全部燒完要耗時1個小時,問如何用這條繩子測出半個小時。    我的答案:假設繩子是鈞勻的,把繩子剪成兩斷,其中一斷燒完,那就是半小時。  

java經典50之4分解質因數

import java.util.Scanner; /** * 題目:將一個正整數分解質因數。例如:輸入90,打印出90=2*3*3*5。    程式分析:對n進行分解質因數,應先找到一個最小的質數k,然後按下述步驟完成:    (1)如果這個質數恰等於n,則說明分解質

區間DP入門之 石子歸併問題 NYOJ 737

分析:要求n個石子歸併,我們根據dp的思想劃分成子問題,先求出每兩個合併的最小代價,然後每三個的最小代價,依次知道n個。 定義狀態dp [ i ] [ j ]為從第i個石子到第j個石子的合併最小代

light oj 1031(區間dp入門

Description You are playing a two player game. Initially there are n integer numbers in an array

Noip 2017 最簡單的

A了這三道題,就可以穩拿一D了(山東) Day1 T1 雖說是個數論題,打表出結論! #include <cstdio> #include <iostream> #define ll long long using namespa

DP區間DP入門

在開始之前我要感謝`y總`,是他精彩的講解才讓我對區間DP有較深的認識。 # 簡介 一般是線性結構上的對區間進行求解最值,計數的動態規劃。大致思路是列舉斷點,然後對斷點兩邊求取最優解,然後進行合併從而得解。 ## 原理 結合模板題(合併石子)講述:https://www.acwing.com/prob

Java經典編程50

個數 [] -- ++ 要求 add example system oid 有一個已經排好序的數組。現輸入一個數,要求按原來的規律將它插入數組中。 public class Example30 { public static void main(String[] a

Java經典編程50十二

out char 輸入 void args pri array int ava 取一個整數a從右端開始的4~7位。 public class Example32 { public static void main(String[] args) { cu

Java經典編程50十七

static new for length print ati class 個人 經典 有n個人圍成一圈,順序排號。從第一個人開始報數(從1到3報數),凡報到3的人退出圈子,問最後留下的是原來第幾號的那位。 public class Example37 { publ

Java經典編程50十八

編程 奇數 n) ret ava for 調用函數 args print 編寫一個函數:輸入n為偶數時,調用函數求1/2+1/4+...+1/n;當輸入n為奇數時,調用函數1/1+1/3+...+1/n。 public class Example38 { publi

Java經典編程50十六

nbsp 移動 編程 move main new for i++ java 有n個整數,使其前面各數順序向後移m個位置,最後m個數變成最前面的m個數。 public class Example36 { public static void main(String[]

經典問題.【環形區間dp】 項鍊 nyoj 460

問題描述: 思路: 在瞭解了一點區間dp的基礎上,我們知道要從小區間最優化推導到大區間最優化。 那麼這題也是一樣:dp[i][j] 代表區間i,j最優釋放的能量。 遞推式:dp[i][j]

Java經典編程50之四

編程題 pub else 整數 正整數分解 clas 因數 stat args 將一個正整數分解質因數。例如:輸入90,打印出90=2*3*3*5。 public class Example04 { public static void main(String[]

Java經典編程50之五

n) pub 嵌套 example void out [] args core 利用條件運算符的嵌套來完成此題:學習成績>=90分的同學用A表示,60-89分之間的用B表示,60分以下的用C表示。 public class Example05 { public

Java經典編程50之八

其中 println i++ class aaa 一個 bsp pub 個數字 求s=a+aa+aaa+aaaa+aa...a的值,其中a是一個數字。例如2+22+222+2222+22222(此時共有5個數相加),幾個數相加由鍵盤控制。 public class Exa

Java經典編程50之七

r++ [] main world else number 字符 英文 ray 輸入一行字符,分別統計出其中英文字母、空格、數字和其它字符的個數。 public class Example07 { public static void main(String[] a

Java經典編程50之九

因子 oid 例如 println out count 它的 編程題 num 一個數如果恰好等於它的因子之和,這個數就稱為"完數"。例如6=1+2+3。編程找出1000以內的所有完數。 public class Example09 { public static v