学会将互不干扰的因素分离考虑(LightOJ-1323 LightOJ-1349)

这两个题都是将二维的运动分离考虑的,最初看到无从下手,分离后情况就简单了许多。

LightOJ-1323

题意:

现在有个矩形长l宽w
矩形内部n个小球,速度相等,方向沿{左上,左下,右上,右下}中间的一个
现在给出n个小球的坐标,问第k秒时这些小球的坐标是什么,要求输出按横纵坐标排序
存在碰撞情况:

1.碰到边界,速度反向
2.两球相碰


输入是T,矩形长度L,W,小球数量N和秒数K,后面N行是小球初始坐标x,y和速度方向(按东西南北给出)

Sample Input

2

 

5 1 1

2 1 10

 

5 5 4

1 1 1

2 2 1

4 4 1

5 5 1

Sample Output

Case 1: 2 1

Case 2: 3 3

思路:

仔细观察两球相撞的情况,可以发现球与球相撞时两球相当于交换了水平或竖直的运动状态,借用学弟的话来说是“有种A和B碰 B走A的原路 A走B的原路”的既视感,而题目要求的是输出排序后球的坐标,那么球与球相撞的情况并不重要,因为相撞后本球的运动状态已经传递给了其他球,另一个球将延续本球的运动状态,相当于啥也没有发生。

那么只考虑球与边界相撞的情况,此时如果将二维的x,y坐标一起考虑将复杂且无用。因为x与y的运动互不干扰,则分开考虑水平和竖直的运动状态,只考虑一维的话问题就会非常简单,将时间k首先模上边界长度l*2,即 k %= 2*l,后将初始位置pos、运动方向和其与边界的距离处理一下即可。

/**

**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
struct node
{
    int x,y;
}p[maxn];
bool cmp(node a, node b)
{
    if(a.x == b.x)
        return a.y<b.y;
    return a.x<b.x;
}
int up(int pos, int l, int k)
{
    int d = k%(l*2);
    int res;
    if(d>l-pos)
    {
        if(d>=2*l-pos)
            res = d+pos-2*l;
        else
            res = 2*l-d-pos;
    }
    else
        res = pos+d;
    return res;
}
int down(int pos, int l, int k)
{
    int d = k%(l*2);
    int res;
    if(d>pos)
    {
        if(d>l+pos)
            res = 2*l-d+pos;
        else
            res = d-pos;
    }
    else
        res = pos-d;
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    int tt = 1;
    while(T--)
    {
        int l,w,n,k;
        cin>>l>>w>>n>>k;
        for(int i = 0; i<n; i++)
        {
            int x,y;
            string s;
            cin>>x>>y>>s;
            if(s[0] == 'N')
                p[i].y = up(y,w,k);
            else
                p[i].y = down(y,w,k);
            if(s[1] == 'E')
                p[i].x = up(x,l,k);
            else
                p[i].x = down(x,l,k);
        }
        sort(p,p+n,cmp);
        cout<<"Case "<<tt++<<":"<<endl;
        for(int i = 0; i<n; i++)
            cout<<p[i].x<<" "<<p[i].y<<endl;
    }

    return 0;
}

LightOJ-1349

题意:

给定q个部落坐标(x,y)和其内部居民数w,要求在m*n网格内部找到一点(a,b)使得所有居民到该点的曼哈顿距离最小。

Sample Input

2

 

5 1 1

2 1 10

 

5 5 4

1 1 1

2 2 1

4 4 1

5 5 1

Sample Output

Case 1: 2 1

Case 2: 3 3

思路:

对于每个点的权值w,可以看做是w个相同点。由于x与y互不干扰,故分离考虑目标点的横纵坐标,此题就转化成了一维坐标的中位数问题。

/**

**/
#include <cstdio>
#include <stack>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#define eps 1e-8
typedef long long ll;
const double PI = acos(-1.0);
const int maxn = 1e6;
const int INF = 0x3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
using namespace std;
struct node
{
    int x,y;
    int w;
}a[maxn];
bool cmp1(node a, node b)
{
    return a.x<b.x;
}
bool cmp2(node a, node b)
{
    return a.y<b.y;
}
int main()
{
    //ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    int tt = 1;
    while(T--)
    {
        int m,n,q;
        scanf("%d%d%d",&m,&n,&q);
        int cnt = 0;
        for(int i = 1; i<=q; i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
            cnt += a[i].w;
        }
        int ansx,ansy;
        int mid = (cnt+1)/2;
        sort(a+1,a+1+q,cmp1);
        int cur = 0;
        for(int i = 1; i<=q; i++)
        {
            cur += a[i].w;
            if(cur>=mid)
            {
                if(cnt&1)
                    ansx = a[i].x;
                else
                {
                    if(cur == mid)
                        ansx = (a[i].x+a[i+1].x)/2;
                    else
                        ansx = a[i].x;
                }
                break;
            }
        }
        sort(a+1,a+1+q,cmp2);
        cur = 0;
        for(int i = 1; i<=q; i++)
        {
            cur += a[i].w;
            if(cur>=mid)
            {
                if(cnt&1)
                    ansy = a[i].y;
                else
                {
                    if(cur == mid)
                        ansy = (a[i].y+a[i+1].y)/2;
                    else
                        ansy = a[i].y;
                }
                break;
            }
        }
        printf("Case %d: %d %d\n",tt++,ansx,ansy);
    }

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值