1. 程式人生 > 其它 >LeetCode:求最大幸福指數

LeetCode:求最大幸福指數

技術標籤:LeetCode動態規劃演算法

You are given four integers,m,n,introvertsCount,and extrovertsCount.You have an mxn grid ,and 
there are two types of people: introverts and extroverts.There are introvertsCount introverts 
and extrovertsCount extroverts.
You should decide how many people you want to live in the grid and assign each of them one 
grid cell.Note that you do not have to have all the people living in the grid.

The happiness of each person is calculated as follows:
(1)Introverts start with 120 happiness and lose 30 happiness for each neighbor(introvert or
 extrovert).
(2)Extroverts start with 40 happiness and gain 20 happiness for each neighbor(introvert or extrovert).
Neighbors live in the directly adjacent cells north,east,south,and west of a person's cell.
The grid happiness is the sum of each person's happiness.Return the maximum possible grid happiness.

Input: m=2, n=3, introvertsCount=1, extrovertsCount=2
Output: 240
Explanation:Assume the grid is 1-indexed with coordinates (row, column).
We can put the introvert in cell (1,1) and put the extroverts in cells (1,3) and (2,3).
-Introvert at (1,1) happiness:120(starting happiness)-(0*30)(0 neighbors)=120
-Extrovert at (1,3) happiness:40(starting happiness)+(1*20)(1 neighbor)=60
-Extrovert at (2,3) happiness:40(starting happiness)+(1*20)(1 neighbor)=60
The grid happiness is 120 + 60 + 60 = 240.
The above figure shows the grid in this example with each person's happiness.The introvert stays in 
the light green cell while the extroverts live on the light purple cells.

解題思路:按行進行狀態壓縮
三進位制:0、1、2,分別表示空、內向、外向
以行為單位進行動態規劃,可以將其分成兩個部分:
(1)同一行內分數:在同一行內每個人的分數,內向120分,外向40分;以及由於兩個人相鄰(下同一行內,即左右相鄰)
貢獻的額外分數,兩個內向-60分,兩個外向40分,其餘情況為-10分;
(2)上下行外分數:由於兩人相鄰(在不同行內,即上下相鄰)貢獻的額外分數,同理為-60,-40,-10分中的一種.
如果規定[上下行外分數]由相鄰兩行中的後一行負責計算,那麼在列舉當前行對應的三進製表示mask時,就需要計算其
與前一行之間的[上下行外分數],因此可以設計出動態規劃中的狀態:
令f(mask,row,nx,wx)表示當我們列舉到第row行且之前的行已經列舉完成,第row-1行狀態為mask,還剩餘nx個
內向的人以及wx個外向的人的情況下,從row行開始往後的所有行可以獲取的最大行數.其狀態轉移方程為:
f(mask,row,nx,wx)=max{f(mask,row+1,nx-countnx(mask),wx-countwx(mask))+scoreinner(mask)+scoreouter(mask)}
countnx/wx(mask)表示狀態馬賽克有多少內向的人/外向的人
(1)每一個mask對應的三進製表示,存放在陣列mask_span中;
(2)countnx(mask)和countwx(mask)分別存在陣列nx_inner和wx_inner;
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;

class Solution{
private:
    int mask_span[729][6];/*預處理,每一個mask的三進位制*/
    int dp[729][6][7][7];/*dp[上一行的mask][當前處理到的行][剩餘的內向人數][剩餘的外向人數]*/
    int nx_inner[729],wx_inner[729],score_inner[729],score_outer[729][729];/*每一個mask包含的內向人數,外向人數,行內得分(只統計mask本身的得分,不包括它與上一行的),行外得分*/
    int m,n,n3;/*n3=3^n*/
private:
    /*x與y的鄰近關係*/
    inline int calc(int x,int y){
        if(x==0||y==0)
           return 0;
        if(x==1&&y==1)
           return -60;
        if(x==2&&y==2)
           return 40;
        return -10;
    }
    
    int dfs(int mask_last,int row,int nx,int wx){
        /*處理完或者沒人*/
        if(row==m||nx+wx==0)
           return 0;
        if(dp[mask_last][row][nx][wx]!=-1)
           return dp[mask_last][row][nx][wx];
        int best=0;
        for(int mask=0;mask<n3;++mask){
            if(nx_inner[mask]>nx||wx_inner[mask]>wx)
               continue;
            int score=score_inner[mask]+score_outer[mask][mask_last];
            best=max(best,score+dfs(mask,row+1,nx-nx_inner[mask],wx-wx_inner[mask]));
        }
        return dp[mask_last][row][nx][wx]=best;
    }
public:
    int getMaxGridHappiness(int m,int n,int nx,int wx){
        this->m=m;
        this->n=n;
        this->n3=pow(3,n);
        for(int mask=0;mask<n3;mask++){
            for(int mask_tmp=mask,i=0;i<n;i++){
                mask_span[mask][i]=mask_tmp%3;
                mask_tmp/=3;
            }
            nx_inner[mask]=wx_inner[mask]=score_inner[mask]=0;
            for(int i=0;i<n;i++){
                if(mask_span[mask][i]!=0){
                    /*個人分數*/
                    if(mask_span[mask][i]==1){
                        nx_inner[mask]++;
                        score_inner[mask]+=120;
                    }else if(mask_span[mask][i]==2){
                        wx_inner[mask]++;
                        score_inner[mask]+=40;
                    }
                    /*行內分數*/
                    if(i-1>=0){
                        score_inner[mask]+=calc(mask_span[mask][i],mask_span[mask][i-1]);
                    }
                }
            }
        }
        /*行外分數*/
        for(int mask0=0;mask0<n3;mask0++){
            for(int mask1=0;mask1<n3;mask1++){
                score_outer[mask0][mask1]=0;
                for(int i=0;i<n;i++){
                    score_outer[mask0][mask1]+=calc(mask_span[mask0][i],mask_span[mask1][i]);
                }
            }
        }
        memset(dp,-1,sizeof(dp));
        return dfs(0,0,nx,wx);
    }
};
int main(int argc,char* argv[]){
    cout<<Solution().getMaxGridHappiness(2,3,1,2)<<endl;
    return 0;
}