HDU 6981.Rise in Price (Beam Search 贪心)
阅读原文时间:2023年08月11日阅读:1

by 0htoAi,写于2021.8.14

There are n×n cells on a grid, the top-left cell is at (1,1) while the bottom-right cell is at (n,n). You start at (1,1) and move to (n,n). At any cell (i,j), you can move to (i+1,j) or (i,j+1), provided that you don't move out of the grid. Clearly, you will make exactly 2n−2 steps.

When you are at cell (i,j), including the starting point (1,1) and the destination (n,n), you can take all the ai,j diamonds at this cell, and have a chance to raise the price of each diamond by bi,j dollars. You will sell all the diamonds you have with the final price in the end, and your goal is to choose the optimal path that will maximize your profits. Note that initially the price of each diamond is zero, and you have nothing to sell.

The first line contains a single integer T (1≤T≤10), the number of test cases. For each test case:

The first line contains a single integer n (1≤n≤100), denoting the size of the grid.

Each of the following n lines contains n integers, the i-th line contains ai,1,ai,2,…,ai,n (1≤ai,j≤106), denoting the number of diamonds in each cell.

Each of the following n lines contains n integers, the i-th line contains bi,1,bi,2,…,bi,n (1≤bi,j≤106), denoting how much you can raise the price in each cell.

It is guaranteed that all the values of ai,j and bi,j are chosen uniformly at random from integers in [1,106]. The randomness condition does not apply to the sample test case, but your solution must pass the sample as well.

For each test case, output a single line containing an integer: the maximum number of dollars you can earn by selling diamonds.

1
4
2 3 1 5
6 3 2 4
3 5 1 4
5 2 4 1
3 2 5 1
2 4 3 5
1 2 3 4
4 3 5 3


528

在一个 \(n\times n\) 的网格内,每格有 \(a_{ij}\) 和 \(b_{ij}\)。从左上角 \((1,1)\) 走到右下角 \((n,n)\)​,每一步只能向下或者向右走。设路径上所有的 \(a_{ij}\) 之和为 \(sa\),\(b_{ij}\) 之和为 \(sb\),求 \(sa \times sb\) 的最大值。

Beam Search(集束搜索)算法,设一个状态包含 \({x,y,sa,sb}\)​ ,且值为 \(sa\times sb\),记录每一个状态的前 \(k\) 大值,一直转移状态直到算出状态 \(x=N\) 且 \(y=N\)​ 的最大值。

用 vector 数组 BEAM 记录每一步的状态,状态限制数 \(MAXHASH\) 设为 \(50\)。

取每个状态的前 \(50\)​​ 大值可以用大根堆来维护。限制状态需要用到数组hash_table记录当前状态数。

现在做法就很明确了,Beam Search代码如下。

点击查看代码

inline long long BEAM_SEARCH()
{
    memset(hash_table,0,sizeof(hash_table));
    BEAM.clear();
    BEAM.push_back(STATE(1,1,a[1][1],b[1][1],(long long)a[1][1]*b[1][1]));
    hash_table[make_hash(1,1)]=1;
    register long long Max=0;
    priority_queue<STATE>q;
    while(BEAM.size()>0)
    {
        for(register int i=0;i<BEAM.size();++i)
        {
            int x=BEAM[i].x,y=BEAM[i].y;
            int sa=BEAM[i].sa,sb=BEAM[i].sb;
            if(x==N&&y==N)
            {
                Max=max(Max,BEAM[i].val);
                continue;
            }
            if(y+1<=N)
            {
                q.push(STATE(x,y+1,sa+a[x][y+1],sb+b[x][y+1],(long long)(sa+a[x][y+1])*(sb+b[x][y+1])));
            }
            if(x+1<=N)
            {
                q.push(STATE(x+1,y,sa+a[x+1][y],sb+b[x+1][y],(long long)(sa+a[x+1][y])*(sb+b[x+1][y])));
            }
        }
        int cnt=BEAM.size();
        BEAM.clear();
        while((!q.empty())&&BEAM.size()<=cnt*MAXHASH)
        {
            if(hash_table[make_hash(q.top().x,q.top().y)]<=MAXHASH)
            {
                BEAM.push_back(q.top());
                hash_table[make_hash(q.top().x,q.top().y)]++;
            }
            q.pop();
        }
    }
    return Max;
}