ACM2021辽宁省赛:D-阿强与网格

146 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

D-阿强与网格

题目描述

阿强在一个N行M列的网格中。
阿强可以用两种方式移动:
向下、向左、向上或向右移动,每次移动的代价为X。换句话说,如果您位于网格的单元格(i,j),则可以转到任意单元格(i+1,j),(i,j−1) ,(i−1,j)或(i,j+1),代价为X。

沿对角线向左下、向右下、向左上、向右上移动成本为Y。换句话说,如果你在网格的单元格(i,j)上,你可以去任意一个单元格(i+1,j−1) ,(i+1,j+1),(i−1,j−1) 或(i−1,j+1),代价为Y。

请你找到从阿强从左上角(1,1)到右下角(N,M)的最小成本。

阿强不能移出网格。

输入描述:

第一行一个整数T(1≤T≤5105)表示数据组数。
接下来T行每行四个整数N,M,X,Y(1≤N,M,X,Y≤106)

输出描述:

对于每组数据一行表示答案。

示例1

输入

3
5 6 2 5
4 7 5 6
7 8 6 5

输出

18
33
36

问题解析

一开始下意识的想BFS,后来发现根本不用那么麻烦(而且也过不了)。

题目已经给定了我们每次操作所花成本,我们可以根据x和y的大小,与网格的形状直接计算得出结果,为了方便,我们认定n比m大:

  1. 如果网格是n *1的形状,此时显然只能用x的方式移动,成本为:**(n-1)x*;
  2. 因为y走一步等于x走两步,所以如果x的两倍小于等于y,我们直接用x走,成本为:**(n+m-2)x*

剩下的情况,我们显然是能用y走就用y走,问题是y改怎么走呢?

一开始想着先对角线移动到底部,然后剩下的用x平移过去:(红色路线)

c5ba00e92e304c009c43b33429d39d36.png

后来发现,其实剩下的位置也是可以斜着走的:(蓝色路线)

8e0e8c3f7c7c4585b365a61fb7c11bd1.png

只不过这么走有约束,即到了底边后,距离终点的距离如果是奇数,则会停在终点的前一格,而这时我们只能用x走了:(橙色路线)

4145b8d5a2554eb2b6266943dfff2e76.png

那么对于其它的情况:我们先走m次y,如果距离终点的距离:n-m是奇数,我们走了(n-m-1)次y后,还要走一次x,成本为:m *y+(n-m-1) *y+x ;如果n-m是偶数,我们直接全走y即可,成本为:m * y+(n-m) * y.

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include <random>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<fstream>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#include<bitset>

#pragma GCC optimize(2)
#pragma GCC optimize(3)

#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 4e5 + 50;

void solve()
{
    int n, m, x, y,ans;
    cin >> n >> m >> x >> y;
    //为了方便,我们保证n比m大
    if(n<m)swap(n,m);
    if(m==1)ans=(n-1)*x;
    else if(x*2<=y)ans=(n+m-2)*x;
    else if(x<=y)ans=(m-1)*y+(n-m)*x;
    else 
    {
        if((n-m)%2==1)ans=(n-2)*y+x;
        else ans=(n-1)*y;
    }
    
    cout<<ans<<endl;
}

signed main()
{

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t = 1;
    cin >> t;

    while (t--)
    {
        solve();
    }
    return 0;
}