區間DP-由矩陣連乘所想到的

1.最優三角剖分

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
#include <set>
#include <math.h>
#include <time.h>

/*=======================================
最優三角剖分
dp[i][j] = min(dp[i][x] + dp[x][j] + w(i, x, j));
i <= x <= j
邊界條件 dp[i][i + 1] == 0
========================================*/
#define flush(arr, i) memset(arr, i, sizeof(arr))
typedef long long int64;
using namespace std;
const int MAX_ITEM = 110;
const int oo = 0x7fffffff;
//const int oo = 0x3f3f3f3f;

int dp[MAX_ITEM][MAX_ITEM], wei[MAX_ITEM][MAX_ITEM];

int GetWeight(int from, int mid, int to)
{
    return wei[from][mid] + wei[from][to] + wei[mid][to];
}


int DP(int from, int to)
{
    if(to - from == 1)
        return 0;
    if(dp[from][to])
        return dp[from][to];

    int ans = oo;
    for(int i = from + 1; i < to; i++)
        ans = min(ans, DP(from, i) + DP(i, to) + GetWeight(from, i, to));

    return dp[from][to] = ans;
}

int main()
{
    freopen("0-data.txt", "r", stdin);
    int n;
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                scanf("%d", &wei[i][j]);
        flush(dp, 0);
        printf("%d\n", DP(0, n - 1));
    }
    return 0;
}
2.最大m子段和

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
#include <set>
#include <math.h>
#include <time.h>

/*=======================================
最大m子段和
9 3
9 8 7 6 5 4 3 2 1
17

dp[k][p]表示前k個元素劃分爲p個子段最大值的最小值

dp[k][p] = min{dp[k][p], max{dp[x][p - 1] + sum[x + 1][k]}}
p - 1 <= x <= k - 1

========================================*/
#define flush(arr, i) memset(arr, i, sizeof(arr))
typedef long long int64;
using namespace std;
const int MAX_ITEM = 110;
const int oo = 0x7fffffff;
//const int oo = 0x3f3f3f3f;

int dp[MAX_ITEM][MAX_ITEM];
int sum[MAX_ITEM];


int DP(int k, int p)
{
    if(p == 1)
        return dp[k][p] = sum[k];

    if(dp[k][p])
        return dp[k][p];

    int tmp = 0;
    dp[k][p] = oo;

    for(int i = p - 1; i <= k - 1; i++)
    {
        tmp = max(DP(i, p - 1), sum[k] - sum[i]);
        dp[k][p] = min(dp[k][p], tmp);
    }

    return dp[k][p];
}

int main()
{
    int len, p;
    while(scanf("%d%d", &len, &p) != EOF)
    {
        flush(sum, 0);
        flush(dp, 0);
        int tmp;
        for(int i = 1; i <= len; i++)
        {
            scanf("%d", &tmp);
            sum[i] = sum[i - 1] + tmp;
        }
        printf("%d\n", DP(len, p));
    }
    return 0;
}
3.石子合併問題

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
#include <set>
#include <math.h>
#include <time.h>

/*=======================================
石子合併問題
自底向上,求步長爲k的時候,步長爲k - 1問題的解已知

dp[i][j]表示i -> j的最優解 得分最多/最少
要加上合併的石子總數作爲最優值
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[i][j]);
========================================*/
#define flush(arr, i) memset(arr, i, sizeof(arr))
typedef long long int64;
using namespace std;
const int MAX_ITEM = 110;
const int oo = 0x7fffffff;
//const int oo = 0x3f3f3f3f;

int dp[MAX_ITEM][MAX_ITEM];
int sum[MAX_ITEM];


int main()
{
    int len;
    while(scanf("%d", &len) != EOF)
    {
        for(int i = 1; i <= len; i++) scanf("%d", sum + i);
        sum[0] = 0;
        for(int i = 1; i <= len; i++)
            sum[i] += sum[i - 1];
        flush(dp, 0);

        for(int sp = 1; sp <= len; sp++)
        {
            for(int i = 1; i + sp <= len; i++)
            {
                int j = i + sp;
                for(int k = i; k < j; k++)
                    dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);
                printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
            }
        }
        printf("%d\n", dp[1][len]);
    }
    return 0;
}
4.最大的算式[TYVJ]

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
#include <set>
#include <math.h>
#include <time.h>

/*=======================================
最大的算式

dp[k][p] = max(dp[p - 1 ... k - 1][p - 1] * sum[k][p])
表示前i部分插入p個乘號獲取的最大值

========================================*/
#define flush(arr, i) memset(arr, i, sizeof(arr))
typedef long long int64;
using namespace std;
const int MAX_ITEM = 110;
const int oo = 0x7fffffff;
//const int oo = 0x3f3f3f3f;

int dp[MAX_ITEM][MAX_ITEM], sum[MAX_ITEM][MAX_ITEM];
int num[MAX_ITEM];

void getSum(int len)
{
    flush(sum, 0);
    flush(dp, 0);
    for(int i = 1; i <= len; i++)
    {
        sum[i][i] = num[i];
        for(int j = i + 1; j <= len; j++)
            sum[i][j] = sum[i][j - 1] + num[j];
    }
/*
    for(int i = 1; i <= len; i++)
        for(int j = i; j <= len; j++)
            j == len ? printf("%d\n", sum[i][j]) : printf("%d ", sum[i][j]);
*/
}

int DP(int k, int p)
{
    if(p == 0)
    {
        dp[k][p] = sum[1][k];
        return dp[k][p];
    }

    if(dp[k][p])
        return dp[k][p];

    int ans = 0;
    for(int i = p - 1; i <= k - 1; i++)
        ans = max(ans, DP(i, p - 1) * sum[i + 1][k]);

    dp[k][p] = ans;
    return ans;
}

int main()
{
    int len, p;
    while(scanf("%d%d", &len, &p) != EOF)
    {
        for(int i = 1; i <= len; i++) scanf("%d", num + i);
        getSum(len);
        printf("%d\n", DP(len, p));
    }
    return 0;
}
5.最大k乘積問題

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <queue>
#include <set>
#include <math.h>
#include <time.h>

/*=======================================
最大k乘積問題

dp[k][p] = max(dp[p - 1 ... k - 1][p - 1] * num[k][p])
表示前i項分爲j部分的最大乘積

========================================*/
#define flush(arr, i) memset(arr, i, sizeof(arr))
typedef long long int64;
using namespace std;
const int MAX_ITEM = 110;
const int oo = 0x7fffffff;
//const int oo = 0x3f3f3f3f;

int dp[MAX_ITEM][MAX_ITEM], num[MAX_ITEM][MAX_ITEM];
char in[MAX_ITEM];

int getNum(char *in)
{
    int len = strlen(in);
    flush(num, 0), flush(dp, 0);
    for(int i = 1; i <= len; i++)
    {
        int mul = 0;
        for(int j = i; j <= len; j++)
        {
            mul = mul * 10 + in[j - 1] - '0';
            num[i][j] = mul;
        }
    }
/*
    for(int i = 1; i <= len; i++)
        for(int j = i; j <= len; j++)
            j != len ? printf("%d ", num[i][j]) : printf("%d\n", num[i][j]);
*/
}

//前k個分爲p部分
int DP(int k, int p)
{
    if(p == 1)
    {
        dp[k][p] = num[1][k];
        return num[1][k];
    }

    if(dp[k][p])
        return dp[k][p];

    int ans = 0;
    for(int i = p - 1; i <= k - 1; i++)
        ans = max(ans, DP(i, p - 1) * num[i + 1][k]);

    dp[k][p] = ans;
    return ans;
}

int main()
{
    int p;
    while(scanf("%s", in) != EOF)
    {
        getNum(in);
        scanf("%d", &p);
        int len = strlen(in);
        printf("%d\n", DP(len, p));
    }
    return 0;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章