Problem C. Matrix Cutting Google Kickstart Round G 2017

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yixin94/article/details/82055146

题意:给定一个M*N矩阵,需要按照横纵轴cut得到M*N个1*1的submatric,每次cut一次得到的coin是矩阵中最小数的值。求最优解是的得到的coin数最大。

small input是一个vector,可以枚举分割的行数。large input想法类似,只不过改成dp,dp[a,b,c,d]表示左上角[a,b]右下角[c,d]的submatrix最优解的情况下得到的coin是多少。状态转移时分别枚举按某一行cut或者按某一列cut:

dp[a,b,c,d]=max(dp[a,b,i,d]+dp[i+1,b,c,d]+min_value[a,b,c,d], dp[a,b,c,j]+dp[a,j+1,c,d]+min_value[a,b,c,d])for all a<=i<c,b<=j<d

min_value[a,b,c,d]表示submatrix中的最小值,可以先O(N^4)预处理。转移时只要和新加入的一列的最小值比较即可。min_value[a,b,c,d]=min(min_value[a,b,c,d-1],min of mp[a~c,d])

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<windows.h>
using namespace std;

//Kcikstart 2017 Round D Problem B. Cards Game
const int maxn=42;
int T;
int N;
int M;
int mp[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];
int min_value[maxn][maxn][maxn][maxn];
int ans;
int dfs(int a,int b,int c,int d)
{
    if(a==c&&b==d)
    {
        return 0;
    }
    if(dp[a][b][c][d]!=0)//each value is >0
    {
        return dp[a][b][c][d];
    }
    int horizon_min=0;
    int vertical_min=0;
    for(int i=a;i<c;i++)//horizontal line
    {
        int val=dfs(a,b,i,d)+dfs(i+1,b,c,d)+min_value[a][b][c][d];
        horizon_min=max(horizon_min,val);
    }
    for(int i=b;i<d;i++)//vertical line
    {
        int val=dfs(a,b,c,i)+dfs(a,i+1,c,d)+min_value[a][b][c][d];
        vertical_min=max(vertical_min,val);
    }
    dp[a][b][c][d]=max(vertical_min,horizon_min);
//    cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<dp[a][b][c][d]<<endl;
    return dp[a][b][c][d];
}
int main()
{
//    freopen("input.txt","r",stdin);
    freopen("C-large-practice.in","r",stdin);
    freopen("C.txt","w",stdout);
    cin>>T;

    for(int ca=1;ca<=T;ca++)
    {
        memset(mp,0,sizeof(mp));
        memset(dp,0,sizeof(dp));
        memset(min_value,0,sizeof(min_value));
        ans=0;
        scanf("%d %d",&N,&M);
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)
            {
                scanf("%d",&mp[i][j]);
            }
        }
        //pre process min value
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)
            {
                min_value[i][j][i][j]=mp[i][j];
                dp[i][j][i][j]=mp[i][j];
            }
        }
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)
            {
                for(int k=i+1;k<N;k++)
                {
                    min_value[i][j][k][j]=min(min_value[i][j][k-1][j],mp[k][j]);
                }
                for(int k=j+1;k<M;k++)
                {
                    min_value[i][j][i][k]=min(min_value[i][j][i][k-1],mp[i][k]);
                }
                for(int l=i+1;l<N;l++)
                {
                    for(int m=j+1;m<M;m++)
                    {
                        int mini=0x3f3f3f3f3f;
                        for(int k=i;k<=l;k++)
                        {
                            mini=min(mini,mp[k][m]);
                        }
                        min_value[i][j][l][m]=min(min_value[i][j][l][m-1],mini);
//                        cout<<i<<" "<<j<<" "<<l<<" "<<m<<" "<<min_value[i][j][l][m]<<endl;
                    }
                }
            }
        }
//        for(int i=0;i<N;i++)
//        {
//            for(int j=0;j<M;j++)
//            {
//                for(int l=i;l<N;l++)
//                {
//                    for(int m=j;m<M;m++)
//                    {
//                        cout<<i<<" "<<j<<" "<<l<<" "<<m<<" "<<min_value[i][j][l][m]<<endl;
//                    }
//                }
//            }
//        }
        ans=dfs(0,0,N-1,M-1);

//        for(int i=0;i<N;i++)
//        {
//            for(int j=0;j<N;j++)
//            {
//                cout<<mp[i][j]<<" ";
//            }
//            cout<<endl;
//        }
        printf("Case #%d: %d\n",ca,ans);
        cerr<<"finish case "<<ca<<endl;


    }
    return 0;
}

附上dfs for small input

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>

using namespace std;

//kickstart 2017 Round G Problem A
int T;
const int maxn=20;
int N;
int M;
int ans;
int mat[maxn][maxn];
int dfs(int st,int ed)//[st,...,ed]
{
    //cout<<st<<" "<<ed<<endl;
    if(st==ed)
    {
        return 0;
    }
    // find min
    int mini=0x3f3f3f3f;
    for(int i=st;i<=ed;i++)
    {
        mini=min(mini,mat[0][i]);
        //cout<<mat[0][i]<<endl;
    }
    int maxret=0;
    for(int i=st;i<ed;i++)
    {
        maxret=max(maxret,dfs(st,i)+dfs(i+1,ed));
    }
    return maxret+mini;
}
int main()
{
    freopen("C-small-attempt0.in","r",stdin);
    //freopen("input.txt","r",stdin);
    freopen("c1.txt","w",stdout);
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        ans=0;
        scanf("%d %d",&N,&M);
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)
            {
                scanf("%d",&mat[i][j]);
            }
        }
        ans=dfs(0,M-1);
        printf("Case #%d: %d\n",ca,ans);

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yixin94/article/details/82055146