2015编程之美,资格赛基站选址问题个人给出的求解

参加了2015的编程之美大赛,被虐惨了,今天贴一下自己的基站选址题的代码,主要的思路就是一直往费用减小的方向走,知道走入最小值得点,可惜大数据测试没过,想想应该是走进了局部最小点。不知道大家有没有什么好方法或者建议,还有就是日后学的东西更多了以后,希望回过头看看自己曾今写的代码和算法,能够不忘初心。

题目:
时间限制:2000ms
单点时限:1000ms
内存限制:256MB
描述
需要在一个N × M的网格中建立一个通讯基站,通讯基站仅必须建立在格点上。

网格中有A个用户,每个用户的通讯代价是用户到基站欧几里得距离的平方。

网格中还有B个通讯公司,维护基站的代价是基站到最近的一个通讯公司的路程(路程定义为曼哈顿距离)。

在网格中建立基站的总代价是用户通讯代价的总和加上维护基站的代价,最小总代价。

输入
第一行为一个整数T,表示数据组数。

每组数据第一行为四个整数:N, M, A, B。

接下来的A+B行每行两个整数x, y,代表一个坐标,前A行表示各用户的坐标,后B行表示各通讯公司的坐标。

输出
对于每组数据输出一行”Case #X: Y”,X代表数据编号(从1开始),Y代表所求最小代价。

数据范围
1 ≤ T ≤ 20

1 ≤ x ≤ N

1 ≤ y ≤ M

1 ≤ B ≤ 100

小数据

1 ≤ N, M ≤ 100

1 ≤ A ≤ 100

大数据

1 ≤ N, M ≤ 107

1 ≤ A ≤ 1000

代码:

// PROGRAM_BEAUTI.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <cmath>


using namespace std;
class vec{
public:
    int x;
    int y;
    bool isInRect( vec rect);
    vec();
    vec(int a, int b);
};

vec::vec()
{
    x = 0; y = 0;
}

vec::vec(int a, int b)
{
    x = a; y = b;
}

bool vec::isInRect( vec rect)
{
    if (x <= rect.x&&y <= rect.y)
        return true;
    else
        return false;
}

vec get_tidu(int num, vec a, vec* b)   //求梯度
{
    int m[2] = {0,0};
    for (int i = 0; i < num; i++)
    {
        m[0] = m[0] + 2 * (a.x - b[i].x);
        m[1] = m[1] + 2 * (a.y - b[i].y);
    }
    vec grad = { m[0], m[1] };
    return grad;
}

int get_okilide_dis(int num, vec a, vec* b)
{
    int dis_sum = 0;
    for (int i = 0; i < num; i++)
    {
        dis_sum = dis_sum + (a.x - b[i].x)*(a.x - b[i].x) + (a.y - b[i].y)*(a.y - b[i].y);
    }
    return dis_sum;
}

vec get_okilide_dis_min(int num, vec* dst)   //距离num个点的最小欧几里得距离,返回最小点
{
    int sumx = 0;
    int sumy = 0;
    for (int i = 0; i < num; i++)
    {
        sumx = dst[i].x + sumx;
        sumy = sumy + dst[i].y;
    }
    vec p_1 = { sumx / num, sumy / num };       //最小点的初始值 去平均数
//  cout << p_1.x <<" "<< p_1.y << endl;
    vec p_2;
    int dis_1,dis_2;
    dis_1 = get_okilide_dis(num, p_1, dst);
    for (;;)
    {
        vec g = get_tidu(num, p_1, dst);
        p_2.x = p_1.x - g.x/10;
        p_2.y = p_1.y - g.y/10;
        if (p_2.x == p_1.x && p_2.y == p_1.y)
            return p_1;
        dis_2 = get_okilide_dis(num, p_2, dst);
        if (dis_1 <= dis_2)
            return p_1;
        else
        {
            p_1 = p_2;
            dis_1 = dis_2;
        }
    }
}

vec get_mahad_dis_min(int n, vec* com, vec p)   //求距离p最近的一家com坐标
{
    int mindis = 0xffff;
    vec min = com[0];
    for(int  i = 0; i < n;i++ )
    {
        int dis = abs(p.x - com[i].x) + abs(p.y - com[i].y);
        if (dis < mindis)
        {
            min = com[i];
            mindis = dis;
        }
    }
    return min;
}

int get_cost(vec* user, int m, vec com, vec p)
{
    int dis1 = get_okilide_dis(m, p, user);
    int dis2 = abs(p.x - com.x) + abs(p.y - com.y);
    return dis1 + dis2;
}

int get_min_from_one(vec p,vec rect,vec *com,int n,vec* user,int m )
{
    for (;;)
    {
        vec p5[5] = { vec(p.x, p.y), vec(p.x, p.y + 1), vec(p.x, p.y - 1), vec(p.x - 1, p.y), vec(p.x + 1, p.y) };
        int dis[5];
        int i = 0;


        for (i = 0; i < 5; i++)
        {
            if (p5[i].isInRect(rect))
            {
                vec p_com = get_mahad_dis_min(n, com, p5[i]);
                dis[i] = get_cost(user, m, p_com, p5[i]);
            }
            else
                dis[i] = -1;
        }

        int min = 0;
        int mindis = dis[0];
        for (i = 1; i < 5; i++)
        {
            if (dis[i] < mindis&&dis[i] >= 0)
            {
                mindis = dis[i];
                min = i;
            }
        }

        if (min == 0)
            return mindis;
        else
            p = p5[min];
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
//  cout << "请输入数据的组数:" << endl;
    int data;
    cin >> data;
    vec* rect = new vec[data];
    vec* mmm = new vec[data];   //保存 用户 公司 组数

    vec **user = new vec*[data];
    vec **com = new vec*[data];

    for (int c = 0; c < data; c++)
    {
//      cout << "请输入第" << c + 1 << "组数据矩形框大小" << endl;
//      cout << "请输入矩阵;" << endl;
        cin >> rect[c].x >> rect[c].y >> mmm[c].x >> mmm[c].y;


        user[c] = new vec[mmm[c].x];
        com[c] = new vec[mmm[c].y];
//      cout << "请输入第" << c + 1 << "组数据的用户矩阵" << endl;
        for (int m = 0; m < mmm[c].x; m++)
        {
            cin >> user[c][m].x >> user[c][m].y;
        }

//      cout << "请输入第" << c + 1 << "组数据的运营商矩阵" << endl;
        for (int m = 0; m < mmm[c].y; m++)
        {
            cin >> com[c][m].x >> com[c][m].y;
        }
    }


    /*vec user[4] = { { 1, 2 }, { 2, 4 }, { 3, 1 }, { 4, 3 } };
    vec rect = { 4, 4 };
    vec com[2] = { vec(1, 4),vec(1,3) };*/
    for (int c = 0; c < data; c++)
    {
        vec point1 = get_okilide_dis_min(mmm[c].x, user[c]);
        //  cout << point1.x <<" "<< point1.y << endl;
        int dis = get_min_from_one(point1, rect[c], com[c], mmm[c].y, user[c], mmm[c].x);
//      cout << dis << endl;

        for (int i = 0; i < mmm[c].y; i++)
        {
            int dis1 = get_min_from_one(com[c][i], rect[c], com[c], mmm[c].y, user[c], mmm[c].x);
            if (dis1 < dis)
                dis = dis1;
        }

        cout << "Case #"<<c+1<<": "<<dis << endl;
    }
    system("pause");
    return 0;
}

你可能感兴趣的:(2015编程之美,资格赛基站选址问题个人给出的求解)