zoukankan      html  css  js  c++  java
  • lightoj1057

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1057

    题目大意:在二维矩阵中,给你一个起点和至多15个的目标点。要你求出从起点出发经过完所有的点后回到起点的最短路径值。每个点一步可以向 八个方向走。

    算法思路:一看就觉得是tsp,用状态压缩。而任意两点的距离就是相应横纵坐标差的较大值。具体看代码。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 1<<16;
    const int INF = 0x3f3f3f3f;
    
    int dp[16][maxn];  //dp[i][S] 表示从起点走完S中的点到达i的最小距离。
    int m,n;
    struct Point{
        int x,y;
        Point(int x=0,int y=0): x(x), y(y) {}
    }P[16],startP;
    int goldnum;
    int dist[16][16];
    
    inline int myfabs(int a){
        if(a < 0) a = -a;
        return a;
    }
    
    int main()
    {
        //freopen("E:\acm\input.txt","r",stdin);
        int T;
        cin>>T;
    
        for(int cas=1; cas<=T; cas++)
        {
            cin>>m>>n;
            char s[20];
            goldnum = 0;
    
            for(int i=0; i<m; i++)
            {
                scanf("%s",s);
                for(int j=0; j<n; j++)
                {
                    if(s[j] == 'x')
                    {
                        startP = Point(i,j);
                    }
                    else if(s[j] == 'g')
                    {
                        P[goldnum++] = Point(i,j);
                    }
                }
            }  //存点。
            memset(dist,0x3f,sizeof(dist));
            for(int i=0; i<goldnum; i++)
                for(int j=i+1; j<goldnum; j++)
            {
                dist[i][j] = dist[j][i] = max(myfabs(P[j].x-P[i].x),myfabs(P[j].y-P[i].y));  //任意两个gold的距离
            }
            for(int i=0; i<goldnum; i++) //把第goldnum看成起点。求起点与任意一个gold的距离。
            {
                dist[goldnum][i] = dist[i][goldnum] = max(myfabs(startP.x-P[i].x),myfabs(startP.y-P[i].y));
            }
    
            int All = (1<<goldnum) - 1;
            memset(dp,0x3f,sizeof(dp));
            dp[0][0];
            for(int i=0; i<goldnum; i++)
            {
                dp[i][1<<i] = dist[goldnum][i];
            }
            for(int S=1; S<=All; S++)
            {
                for(int i=0; i<goldnum; i++)
                {
                    if(S & (1<<i))  //S中包含了i这点。
                    {
                        for(int j=0; j<goldnum; j++)
                        {
                            if(S & (1<<j)) continue;  //要取不在S中的点j
                            dp[j][S|(1<<j)] = min(dp[j][S|(1<<j)],dp[i][S] + dist[i][j]);
                        }
                    }
                }
            }
            int ans = INF;
            for(int i=0; i<goldnum; i++)
                ans =min(ans,dp[i][All] + dist[i][goldnum]);
    
            if(ans == INF) ans = 0;   //这个坑,WA了几次
            printf("Case %d: %d
    ",cas,ans);
        }
    }
    /**
    Keep in mind that, when you receive a WA and want to find "critical" cases,
    it's often useful to start by thinking of cases that go to either extreme 
    of the specifications (either the largest or lowest numbers possible).
    It doesn't take a lot of practice to get in a frame of mind in which,
    when you read something like "There will be exactly one 'x' in the city 
    and at most 15 gold positions", you almost immediately make the connection to 
    think of a test case with either 0 or 15 gold and try that.
    **/
    View Code
  • 相关阅读:
    CXF入门案例
    计算python内部数据结构时间效率-源代码
    笨办法学习python-ex41源码加自己注释
    python之random模块
    python之模块、类、对象
    购物车代码
    ql的python学习之路-day1
    数组转置(函数指针,回调函数)
    将一句话按单词逆转
    *一个二级指针的练习(输入一个数,输出对应的月份)
  • 原文地址:https://www.cnblogs.com/acmdeweilai/p/3330446.html
Copyright © 2011-2022 走看看