关闭

SRM538-div1-2-TurtleSpy

标签: 360string算法systemclassjava
170人阅读 评论(0) 收藏 举报
分类:

题目大意:
     机器人从起始点开始,可以有个四种动作:
  • 前进X距离
  • 后退X距离
  • 向左旋转X度(1到359之间)
  • 向右旋转X度(1到359之间)
     现在给出一组动作的集合,动作的顺序未知,求该组动作按照一定的次序排列后得到的最大移动距离。
     数据规模:X为[1,1000],动作集合大小为[1,50]
     
     
思路:
     求解这道题的关键在于要观察到如下特点:
  • 旋转的动作是可选的,因为可以把这些旋转动作放在最后,那么对最终位置就不会有任何影响。
  • 最优移动策略中,前进的动作应该是连续的,后退的动作也应该是连续的。也就是说最优路径应该如下图所示,其中蓝色是前进的路线,红色是后退的路线。其中theta夹角表示两条路线之间旋转过的角度。


     第二个特点,看起来比较直观。凭直觉的话,不同的前进(或者后退)动作之间如果加入了旋转动作,那么走出来的路线是曲折的路线,距离必然会小于走直线的路线,所以最优路线应该是先往一个方向前进再往一个方向后退。虽然该命题是正确的(因为通过system test了),但是这种分析并不严谨,需要更加严格的证明,目前本人没想出证明方法。
     建立在这两个特点之上,我们所要解决的问题其实就是找到一个合适的theta使得最终距离最大,根据余弦定理:
                         c=sqrt(a^2+b^2-2*a*b*cost(theta))
theta越接近180度,c的值越大。所以我们需要从所有旋转角度的动作中找到一个组合使得theta的值最接近180度。
     由于角度的取值范围只能是[0,359]中的整数,所以可以用dp算法获得所有可能的角度值,然后选取其中最接近180度的。dp过程与背包问题类似,每考虑一个旋转动作记录一次已有的角度值即可。算法复杂度O(360*n),其中n为旋转动作数。

Java代码:

public class TurtleSpy {
    public double maxDistance(String[] commands) {
        long f = 0, b = 0;
        ArrayList<Integer> angle = new ArrayList<Integer>();
        for (int i = 0; i < commands.length; ++i) {
            String[] ss = commands[i].split(" ");
            int x = Integer.parseInt(ss[1]);
            if (ss[0].equals("forward")) {
                f += x;
            } else if (ss[0].equals("backward")) {
                b += x;
            } else if (ss[0].equals("left")) {
                angle.add(-x);
            } else {
                angle.add(x);
            }
        }
        boolean[] dp = new boolean[360];
        dp[0] = true;
        for (int i = 0; i < angle.size(); ++i) {
            boolean[] next = new boolean[360];
            for (int a = 0; a < 360; ++a){
                if (dp[a]) {
                    next[(a + 360 + angle.get(i)) % 360] |= dp[a];
                    next[a] |= dp[a];
                }
            }
            dp = next;
        }
        int theta = 0;
        for (; theta < 180; ++theta) {
            if (dp[180 - theta] || dp[180 + theta]) {
                break;
            }
        }
        return Math.sqrt(Math.abs(f * f + b * b + 2 * f * b * Math.cos(Math.PI * theta / 180)));
    }
}



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:26809次
    • 积分:743
    • 等级:
    • 排名:千里之外
    • 原创:22篇
    • 转载:35篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论