• poj3034 WhacaMole


    dp

    先自己写了一个。。 n次WA后搞成TLE~ 。。。  忍无可忍。。 后来参考了网上的代码。 最终AC~

    先贴人家的代码吧~

    【转】

    思路:DP。改了要一天,很纠结的一道题。DP部分,dp[t][x][y]表示第t时间把锤子停在(x,y)上最多能够打到的地鼠数量。则dp[t][x][y] = max(dp[t-1][xx][yy] + (xx,yy)到点(x,y)新打的地鼠数),(xx,yy)和(x,y)的直线距离<d。但是最主要的是下面两点:

    1:中转点可能在区域外,如下数据:    //相当重要!!!

    20 5 4
    1 0 1
    0 1 1
    0 5 2
    1 6 2
    答案应该是4而不是3,这就需要扩展区域为n+2d就够啦。

    2:(xx,yy)到点(x,y)新打的地鼠数的求法。这点纠结了很久,若一个点在线段(xx,yy)(x,y)上,则这一点上面的地鼠也会被打到。还是看代码吧....

     

    源代码:(464K,563MS)

    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #define max(a,b) ((a)>(b)?(a):(b))
    using namespace std;

     

    struct data{
        int dx, dy, dw;
    }ste[100];
    int n, N, d, m, k;
    int dp[15][50][50];
    int map[15][50][50];

     

    bool cmp(data a, data b){
        return a.dw < b.dw;
    }

     

    bool inMap(int x, int y){
        if(x >= 0 && x <= N && y >= 0 && y <= N) return true;
        return false;
    }

     

    int gcd(int a, int b){    //最大公因数
        if(b == 0)  return a;
        return gcd(b, a%b);
    }

     

    int getSum(int t, int x, int y, int xx, int yy, int dx, int dy){
        int sum = 0;
        do{
            x += dx, y += dy;
            sum += map[t][x][y];
        }while(!(x == xx && y == yy));
        return sum;
    }

     

    int main(){
        int t, i, T, sum;
        int x, y, xx, yy, dx, dy;
        for(k = 0, x = -5; x <= 5; x ++)    //  先预处理5步内所有可能的走法。(d<=5)
            for(y = -5; y <= 5; y ++)
                if(x*x + y*y <= 25){
                    ste[k].dx = x;
                    ste[k].dy = y;
                    ste[k ++].dw = ceil(sqrt(0.0+x*x+y*y));
                }
        sort(ste, ste+k, cmp);
        while(scanf("%d%d%d", &n, &d, &m) && n){
            memset(dp, 0, sizeof(dp));
            memset(map, 0, sizeof(map));
            T = -1;
            while(m --){
                scanf("%d%d%d", &x, &y, &t);
                map[t][x+d][y+d] = 1;
                T = max(T, t);
            }
            T ++, N = n+2*d;   //   扩展区域。
            for(t = 1; t < T; t ++)
                for(x = 0; x <= N; x ++)
                    for(y = 0; y <= N; y ++)
                        for(i = 0; ste[i].dw <= d && i < k; i ++){
                            dx = ste[i].dx;
                            dy = ste[i].dy;
                            xx = x + dx;
                            yy = y + dy;
                            if(!inMap(xx, yy)) continue;
                            if(i == 0) sum = map[t][x][y];
                            else{        //  求(xx,yy)到(x,y)线段上能打到的地鼠数,gcd()用得很巧。
                                int tmp = gcd(abs(dx), abs(dy));
                                dx = dx / tmp;
                                dy = dy / tmp;
                                sum = map[t][x][y] + getSum(t, x, y, xx, yy, dx, dy);
                            }
                            dp[t+1][xx][yy] = max(dp[t+1][xx][yy], dp[t][x][y] + sum);
                        }
            int ans = 0;
            for(x = d; x < n+d; x ++)
                for(y = d; y < n+d; y ++)
                        ans = max(ans, dp[T][x][y]);
            printf("%d\n", ans);
        }
        return 0;
    }

    最后贴上我的TLE代码~

    思路一样。。 只是处理点是否在直线上的方式不同。。

    /*
     * 3034.cpp
     *
     *  Created on: 2011-7-9
     *      Author:
     */

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;

    const double eps = 1e-6;
    int n, d, m;
    int dp[1000 + 5][50 + 5][ 50 + 5] = {};
    int p[1000 + 5][50 + 5][50 + 5] = {};  //mole的情况

    int main(){
        while(true){
            //输入
            scanf("%d%d%d", &n, &d, &m);
            if(n == 0) return 0;

            memset(dp, 0, sizeof(dp));
            memset(p, 0, sizeof(p));
            int max_t = -1, _x, _y, _t;
            for(int i=0; i<m; i++){
                scanf("%d%d%d", &_x, &_y, &_t);
                _x += d; _y += d;
                p[_t][_x][_y] = 1;
                if(max_t < _t) max_t = _t;
            }

            //……
            for(int it=1; it<=max_t; it++){
                for(int ix=0; ix<=n+2*d; ix++){
                    for(int iy=0; iy<=n+2*d; iy++){

                        for(int ixx=0; ixx<=n+2*d; ixx++){
                            for(int iyy=0; iyy<=n+2*d; iyy++){
                                if(ixx != ix && (ixx - ix) * (ixx - ix) + (iyy - iy) * (iyy - iy) <= d * d){
                                    double k = ((double)iyy - iy) / (ixx - ix);    //斜率, 要求ixx!=ix
                                    int dx = (ixx > ix ? -1 : 1);
                                    int dy = (iyy > iy ? -1 : 1);
                                    int tmp_mole = dp[it-1][ixx][iyy];
                                    for(int gx=ixx; gx!=ix+dx; gx+=dx){    //iyy 可以 = iy
                                        for(int gy=iyy; gy!=iy+dy; gy+=dy){
                                //            if(fabs(k * (gx - ix) - gy + iy) <= eps){  //这样的话WA~
                                            if(((double)gy - iy) / (gx - ix) - k <= eps && (gx-ix)*(gx-ixx) <= 0){  // 斜率相等且点在起点和终点之间 TLE 囧~
                                                tmp_mole += p[it][gx][gy];
                                            }
                                        }
                                    }

                                    if(dp[it][ix][iy] < tmp_mole)
                                        dp[it][ix][iy] = tmp_mole;

                                }
                                else if(ixx == ix && iyy - iy <= d){      //ixx == ix 的情况
                                    int dy = (iyy > iy ? -1 : 1);
                                    int tmp_mole = dp[it-1][ixx][iyy];
                                    for(int gy=iyy; gy!=iy+dy; gy+=dy){
                                        if(p[it][ix][gy]) tmp_mole++;
                                    }
                                    if(dp[it][ix][iy] < tmp_mole)
                                        dp[it][ix][iy] = tmp_mole;
                                }
                            }
                        }


                    }
                }
            }

            int ans = -1;
            for(int i=d; i<n+d; i++){
                for(int j=d; j<n+d; j++){
                    if(dp[max_t][i][j] > ans)
                        ans = dp[max_t][i][j];
                }
            }

            printf("%d\n", ans);


        }


        return 0;
    }





  • 相关阅读:
    小学四则算式扩充
    软件工程初涉之感
    回头
    个人最终总结
    团队作业
    结对编程
    老李的blog使用日记(3)
    进度
    老李的blog使用日记(2)
    红果果
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2101863.html
Copyright © 2020-2023  润新知