Round C APAC Test 2017 Problem A. Monster Path

Problem A. Monster Path

Codejamon is a mobile game in which monster trainers walk around in the real world to catch monsters. You have an old smartphone with a short battery life, so you need to choose your path carefully to catch as many monsters as possible.

Suppose the Codejamon world is a rectangular grid with R rows and C columns. Rows are numbered from top to bottom, starting from 0; columns are numbered from left to right, starting from 0. You start in the cell in the Rsth row and the Csth column. You will take a total of S unit steps; each step must be to a cell sharing an edge (not just a corner) with your current cell.

Whenever you take a step into a cell in which you have not already caught a monster, you will catch the monster in that cell with probability P if the cell has a monster attractor, or Qotherwise. If you do catch the monster in a cell, it goes away, and you cannot catch any more monsters in that cell, even on future visits. If you do not catch the monster in a cell, you may still try to catch the monster on a future visit to that cell. The starting cell is special: you have no chance of catching a monster there before taking your first step.

If you plan your path optimally before making any move, what is the maximum possible expected number of monsters that you will be able to catch?

The battery can only support limited steps, so hurry up!

Input

The first line of the input gives the number of test cases, TT test cases follow.

Each test case starts with a line of five integers: RCRsCs and SR and C are the numbers of rows and columns in the grid; Rs and Cs
are the numbers of the row and column of your starting position, and S is the number of steps you are allowed to take.

The next line contains two decimals P and Q, where P is the probability of meeting a monster in cells with a monster attractor, and Q is the probability of meeting a monster in cells without a monster attractor. P and Q are each given to exactly four decimal places.

Each of the next R lines contains contains C space-separated characters; the j-th character of the i-th line represents the cell at row i and column j. Each element is either .(meaning there is no attractor in that cell) or A (meaning there is an attractor in that cell).

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the largest possible expected number of monsters that the player can catch in the given amount of steps.

y will be considered correct if y is within an absolute or relative error of 10-6 of the correct answer. See the FAQ for an explanation of what that means, and what formats of real numbers we accept.

Limits

1 ≤ T ≤ 100.
0 ≤ Rs < R.
0 ≤ Cs < C.
0 ≤ Q < P ≤ 1.

Small dataset

1 ≤ R ≤ 10.
1 ≤ C ≤ 10.
0 ≤ S ≤ 5.

Large dataset

1 ≤ R ≤ 20.
1 ≤ C ≤ 20.
0 ≤ S ≤ 9.

Sample


Input 
 

Output 
 
2
4 4 0 0 5
0.8000 0.2000
. . . .
. . . .
. . A .
. A . A
10 10 9 1 4
0.6121 0.1000
. . A A . . . . . .
A . . . . . . . . .
. . A . . . . A . .
. . . A A . . . . .
. A A A . . . . . A
A . A A . . . . A .
. A . . . . . A . .
. . . . A A . . . .
. . A . . . A . . A
. . . . A . . A . .
Case #1: 1.6000000
Case #2: 1.0495336

In Case #1, one of the best paths is (0,0)->(0,1)->(0,2)->(1,2)->(2,2)->(2,3). On this path, the expected number of monsters that you will catch is 0.2 + 0.2 + 0.2 + 0.8 + 0.2 = 1.6. Remember that there is no chance of catching a monster before taking your first step, which is why there are five probabilities in the calculation, not six.

In Case #2, one of the best paths is (9,1)->(9,2)->(8,2)->(8,3)->(8,2). On this path, the expected number of monsters that you will catch is 0.1 + 0.6121 + 0.1 + 0.23743359 = 1.04953359. Since we accept results within an absolute or relative error of 10-6 of the correct answer (1.04953359), 1.0495336 is accepted.

Solution

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <utility>
#include <cmath>
#include <cstring>
#include <iomanip>
using namespace std;

typedef long long ll;

const int MAXN = 20;
double ori_grid[MAXN][MAXN], grid[MAXN][MAXN];

double get_res(int R, int C, double grid[MAXN][MAXN], int Rs, int Cs, int S, double res)
{
    if (Rs < 0 || Cs < 0 || Rs >= R || Cs >= C)
        return 0.0;

    double ori = grid[Rs][Cs];
    res += ori;
    S--;
    // printf("get_res %d %d %d %f\n", Rs, Cs, S, res);
    if (S == 0)
        return res;

    grid[Rs][Cs] = ori * (1 - ori_grid[Rs][Cs]);

    double res1 = get_res(R, C, grid, Rs - 1, Cs, S, res);
    double res2 = get_res(R, C, grid, Rs + 1, Cs, S, res);
    double res3 = get_res(R, C, grid, Rs, Cs - 1, S, res);
    double res4 = get_res(R, C, grid, Rs, Cs + 1, S, res);
    // printf("get_res %f %f %f %f\n", res1, res2, res3, res4); 

    grid[Rs][Cs] = ori;

    return max(max(res1, res2), max(res3, res4));
}

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "Invalid input" << endl;
        return 1;
    }

    int T = 0;
    string input = argv[1];
    string output = input.substr(0, input.length() - 2) + "out";
    
    ifstream in(input.c_str());
    if (!in.is_open())
    {
        cout << "Error opening file" << endl;
        return 2;
    }

    in >> T;
    int R = 0, C = 0, S = 0;
    int Rs = 0, Cs = 0;
    double P = 0, Q = 0;
    double res = 0;
    ofstream out(output.c_str());
    for (int i = 1; i <= T; i++)
    {
        in >> R >> C >> Rs >> Cs >> S >> P >> Q;
        memset(ori_grid, 0, MAXN * MAXN * sizeof(double));
        memset(grid, 0, MAXN * MAXN * sizeof(double));
        char ch = '\0';
        for (int r = 0; r < R; r++)
        {
            for (int c = 0; c < C; c++)
            {
                in >> ch;
                if (ch == 'A')
                    ori_grid[r][c] = grid[r][c] = P;
                else
                    ori_grid[r][c] = grid[r][c] = Q;
                // cout << grid[r][c] << " ";
            }
            // cout << endl;
        }
        if (S > 0 && R * C > 1)
        {
            double res1 = get_res(R, C, grid, Rs - 1, Cs, S, 0.0);
            double res2 = get_res(R, C, grid, Rs + 1, Cs, S, 0.0);
            double res3 = get_res(R, C, grid, Rs, Cs - 1, S, 0.0);
            double res4 = get_res(R, C, grid, Rs, Cs + 1, S, 0.0);
            // printf("%f %f %f %f\n", res1, res2, res3, res4); 
            res = max(max(res1, res2), max(res3, res4));
        }
        else
            res = 0.0;
        out << "Case #" << i << ": " << setiosflags(ios::fixed) << setprecision(7) << res << endl;
        cout << "Case #" << i << ": " << setiosflags(ios::fixed) << setprecision(7) << res << endl;
    }

    return 0;
}


Note


注意在重复访问重复cell的时候,捕获概率和逃跑概率的计算。


Problem Reference


https://code.google.com/codejam/contest/6274486/dashboard

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EnjoyCodingAndGame

愿我的知识,成为您的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值