美文网首页
邮局(深搜+剪枝)

邮局(深搜+剪枝)

作者: 碧影江白 | 来源:发表于2017-03-05 17:18 被阅读34次

    题目如下:

    问题描述
      C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流。为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信。
    
      现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
    输入格式
      输入的第一行包含三个整数n, m, k,分别表示村民的户数、备选的邮局数和要建的邮局数。
      接下来n行,每行两个整数x, y,依次表示每户村民家的坐标。
      接下来m行,每行包含两个整数x, y,依次表示每个备选邮局的坐标。
      在输入中,村民和村民、村民和邮局、邮局和邮局的坐标可能相同,但你应把它们看成不同的村民或邮局。
    输出格式
      输出一行,包含k个整数,从小到大依次表示你选择的备选邮局编号。(备选邮局按输入顺序由1到m编号)
    样例输入
    5 4 2
    0 0
    2 0
    3 1
    3 3
    1 1
    0 1
    1 0
    2 1
    3 2
    样例输出
    2 4
    数据规模和约定
      对于30%的数据,1<=n<=10,1<=m<=10,1<=k<=5;
      对于60%的数据,1<=m<=20;
      对于100%的数据,1<=n<=50,1<=m<=25,1<=k<=10。
    

    这道题使用的方法是剪枝+深搜。
    解题步骤在于:
    先设定一个邮局是已确定的,得出所有的村民到该邮局的距离。
    再逐个进行判断未确定的邮局,如果该邮局到所有村民家的距离都大于当前最小值,那么该邮局被剪枝,即被放弃。
    直到找遍所有的邮局且邮局数目为当前数目。
    使用方法深搜则在于,每当确定一个邮局,那么下一个参数的传递值则加一,来标记已确定邮局数目。
    其中需要注意到的是,从大到小首先确定一个数,然后从大到小依次判断是否可留,如果是,那么替换当前已确定最小数,否则,被剪枝。继续迭代。

    #include<iostream>  //邮局  
    #include<stdlib.h>
    #include<math.h>
    using namespace std;
    int n, m, k, j, c[55][2], y[27][2], d[12], f1, f2, f[55] = { 0 };
    float yc[27][55], s = 1000000000;
    int dfs(int t, int i, int o[12], float w[55], float sum)
    {
        if (i <= m + 1)//如果还没有遍历完所有的邮局
        {
            if (t == k)//如果已经确定的邮局数已足够
            {
                if (sum<s)
                {
                    s = sum;//s是最后的最小距离总值
                    for (j = 0; j<k; j++)
                        d[j] = o[j];//将数组o的k个值存入数组d
                }
            }
            else if (i <= m&&t<k)//还没有确定所有邮局数
            {
                float ww[55];
                for (j = 1; j <= n; j++)
                    ww[j] = w[j];
                dfs(t, i + 1, o, w, sum); f1 = 1, f2 = 0;//下一个邮局,初始化两个标记用的变量f1,f2
                if (!f[i])//f[i]==0,还没有被剪掉
                {
                    o[t] = i;//第t个已确定邮局是i
                    if (t>0)//ww初始化已经
                    {
                        f2 = 1;
                        for (j = 1; j <= n; j++)
                        {
                            if (ww[j]>yc[i][j])//如果邮局到村民家的距离小于当前最小
                            {
                                sum = sum - ww[j] + yc[i][j];//更新
                                ww[j] = yc[i][j];
                                f1 = 0;//变化,不剪掉当前邮局
                            }
                        }
                    }
                    else//还没有初始化
                    {
                        for (j = 1; j <= n; j++)
                        {
                            sum += yc[i][j];
                            ww[j] = w[j] = yc[i][j];//初始化最小值就是当前值
                        }
                    } 
                    if (f1&&f2)//已经有过ww初始化且需要剪掉当前的邮局,ww如果未初始化那么一定不能剪掉
                    {
                        f[i] = 1;//经过处理,已经被剪掉
                        dfs(t, i + 1, o, w, sum);//下一次迭代t不增加
                    }
                    else
                        dfs(t + 1, i + 1, o, ww, sum);//下一次迭代
                }
            }
        }
    }
    int main()
    {
        int i, j, o[12];
        float w[55], ww[55];
        cin >> n >> m >> k;
        for (i = 1; i <= n; i++)
            cin >> c[i][0] >> c[i][1];
        for (i = 1; i <= m; i++)
        {
            cin >> y[i][0] >> y[i][1];
            for (j = 1; j <= n; j++)
                yc[i][j] = sqrt((c[j][0] - y[i][0])*(c[j][0] - y[i][0]) + (c[j][1] - y[i][1])*(c[j][1] - y[i][1]));
        }//yc[i][j]代表第i个邮局到第j个村民家的距离
        dfs(0, 1, o, w, 0);
        for (i = 0; i<k; i++)
            cout << d[i] << " ";
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:邮局(深搜+剪枝)

          本文链接:https://www.haomeiwen.com/subject/lvvjgttx.html