2019杭电多校训练七 hdu 6653 Halt Hater

5 篇文章 0 订阅
1 篇文章 0 订阅

学大佬的暴力打表找规律,大佬打的表看不懂,自己打了一份。先看看表

当a=8 b=9的时候,规律很明显了
当a=8 b=8的时候规律是一样的
经过测试当a<=b的时候,规律相同
在这里插入图片描述
当a>b的时候规律发生变化,经过测试,当a>b && a<2*b 的时候规律相同

当 a>= 2b 的时候,又一个规律
把坐标轴分成四个部分,用那四个零点当原点,判断终点应该对应哪个原点
现在规律总结一下:
1.当a<=b的时候,答案就是终点到原点的水平距离和垂直距离中最大的那个值乘a
2.当a>b && a<=2b 答案是终点到原点的水平距离和垂直距离中最大的值乘b加上最小的值乘b-a
3.当a>=2b 答案是终点到原点的水平距离和垂直距离之和乘b

接下来是我的打表代码,是用bfs打的

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <algorithm>
typedef long long ll;
using namespace std;
const ll mod=998244353;
const int maxn=1e6+100;

int mp[1000][1000][4],vis[1000][1000][4];
int xx[5][5]={{0,1},{0,-1},{-1,0},{1,0}};
int a,b;
struct nn
{
    int x,y,k;
    nn(){}
    nn(int x,int y,int k):x(x),y(y),k(k){}
};

int check(int k,int i)
{
    if(k==0 && i==0)return 0;
    if(k==1 && i==2)return 0;
    if(k==2 && i==1)return 0;
    if(k==3 && i==3)return 0;
    return 1;
}

int getnexk(int i)
{
    if(i==0)return 2;
    if(i==1)return 0;
    if(i==2)return 3;
    if(i==3)return 1;
}

int getcost(int k,int nexk)
{
    if(k==nexk)return b;
    if(k==0 && nexk==3)return a;
    if(k==1 && nexk==0)return a;
    if(k==2 && nexk==1)return a;
    if(k==3 && nexk==2)return a;
    return 0;
}

void bfs()
{
    queue<nn>q;
    q.push(nn(500,500,0));
    int cnt=0;
    while(!q.empty()){
        nn now=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            int x=now.x+xx[i][0];
            int y=now.y+xx[i][1];
            if(check(now.k,i)==0)continue;
            int nexk=getnexk(i);
            int cost=getcost(now.k,nexk);
            if(abs(500-x)>10 || abs(500-y)>10)continue;
            if(vis[y][x][nexk]==0){
                mp[y][x][nexk]=mp[now.y][now.x][now.k]+cost;
                vis[y][x][nexk]=1;
                q.push(nn(x,y,nexk));
            }
            else if(mp[y][x][nexk]>mp[now.y][now.x][now.k]+cost){
                mp[y][x][nexk]=mp[now.y][now.x][now.k]+cost;

                q.push(nn(x,y,nexk));
            }
        }
    }
//    cout<<mp[502][502][2]<<endl;
    for(int i=492;i<=509;i++){
        for(int j=492;j<=509;j++){
            if(i==500 && j==500)printf("%3d",-1);
            else
            printf("%3d",min(min(mp[i][j][0],mp[i][j][1]),min(mp[i][j][2],mp[i][j][3])));
        }cout<<endl;
    }
}


int main() {
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    scanf("%d%d",&a,&b);
    bfs();

    return 0;
}

接下来是我的ac代码,写的有点麻烦,但是当时为了找规律没管他

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <algorithm>
typedef long long ll;
using namespace std;
const ll mod=998244353;
const int maxn=1e6+100;

ll a,b,x,y;

int jud()
{
    if(x>=1 && y>=0)return 1;
    if(x<=0 && y>=0)return 2;
    if(x<=0 && y<=-1)return 3;
    if(x>=1 && y<=-1)return 4;
}

ll solve1(ll c,ll d)
{
    ll len=max(labs(x-c),labs(y-d));
    return len*a;
}

ll solve2(ll c,ll d)
{
    return max(labs(x-c),labs(y-d))*b+min(labs(x-c),labs(y-d))*(a-b);
}

ll solve3(ll c,ll d)
{
    return (labs(x-c)+labs(y-d))*b;
}

int main() {
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld%lld%lld",&a,&b,&x,&y);
        ll ans=0;
        int xiang=jud();
        if(a<=b){
            if(xiang==1)ans=solve1(1,0);
            if(xiang==2)ans=solve1(0,0);
            if(xiang==3)ans=solve1(0,-1);
            if(xiang==4)ans=solve1(1,-1);
        }
        else if(a>b && a<2*b){
            if(xiang==1)ans=solve2(1,0);
            if(xiang==2)ans=solve2(0,0);
            if(xiang==3)ans=solve2(0,-1);
            if(xiang==4)ans=solve2(1,-1);
        }
        else{
            if(xiang==1)ans=solve3(1,0);
            if(xiang==2)ans=solve3(0,0);
            if(xiang==3)ans=solve3(0,-1);
            if(xiang==4)ans=solve3(1,-1);
        }
        printf("%lld\n",ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值