题目意思是给出平面上n个不相邻的点,要求到这n个点的曼哈顿距离之和最小的点的个数ans2,和这个最小距离ans1。
点的坐标范围是-10000到10000(这个很重要)

考虑到曼哈顿距离的定义:|x - x0| + |y - y0|
这个定义是线性的,对称的
因此考虑分别在两个方向上解这个问题(曼哈顿距离的性质)

1。对于x方向,定义x曼哈顿距离是|x - x0|,因为坐标范围很小,所以可以对所有可能的坐标,做一个线性扫描,求出fx,fx[x0]表示所有点到x0这个x坐标的x曼哈顿距离之和。对y方向相应地求出fy。
2。有了fx和fy,我们可以用O(1)时间算出所有点到某一坐标(x0, y0)的曼哈顿距离之和ans1。现在选出fx[x0] + fy[y0]的最小值(剔除那些输入的点),这一步我是把fx和fy分别排序做的,复杂度O(nlogn)。应该能利用点的不相邻性质做得更好。
3。现在统计满足题意的点的个数。利用fx计算数组nx,nx[i].coor表示此点的x坐标,nx[i].num表示x坐标是nx[i].coor的点的个数,nx[i].dist表示所有点到nx[i].coor的x曼哈顿距离之和。相应地计算ny。计算数组dd,dd[i]表示所有点到第i个点的曼哈顿距离之和。令t1 = sum(nx[i].num * ny[i].num), if (nx[i].dist + ny[i].dist == ans1)。令t2 = (dd[i] == ans1) 的个数。因此ans2 = t1 - t2。

下面是我的代码:

/*************************************************************************
Author: WHU_GCC
Created Time: 2008-1-19 20:26:13
File Name: pku3269.cpp
Description: 
***********************************************************************
*/

#include 
<iostream>
#include 
<set>
using namespace std;

#define out(x) (cout << #x << ": " << x << endl)
typedef 
long long int64;
const int maxint = 0x7FFFFFFF;
const int64 maxint64 = 0x7FFFFFFFFFFFFFFFLL;
template 
<class T> void show(T a, int n) for (int i = 0; i < n; ++i) cout << a[i] << ' '; cout << endl; }
template 
<class T> void show(T a, int r, int l) for (int i = 0; i < r; ++i) show(a[i], l); cout << endl; }

const int maxn = 10010;

struct node_t
{
    
int dist;
    
int coor;
}
;

struct num_t
{
    
int dist;
    
int num;
}
;

bool operator <(const node_t &a, const node_t &b)
{
    
return a.dist < b.dist;
}


int n;
int x[maxn];
int y[maxn];
node_t fx[maxn 
* 2];
node_t fy[maxn 
* 2];
int hx[maxn * 2];
int hy[maxn * 2];
int minx, miny, maxx, maxy;
int dd[maxn];

set <pair<intint> > ptrset;

num_t nx[maxn];
num_t ny[maxn];
int lnx, lny;

int main()
{
    scanf(
"%d"&n);
    memset(hx, 
0sizeof(hx));
    memset(hy, 
0sizeof(hy));
    
    minx 
= miny = maxint;
    maxx 
= maxy = 0;
    ptrset.clear();
    
for (int i = 0; i < n; i++)
    
{
        scanf(
"%d%d"&x[i], &y[i]);
        x[i] 
+= 10000;
        y[i] 
+= 10000;
        ptrset.insert(make_pair(x[i], y[i]));
        hx[x[i]]
++;
        hy[y[i]]
++;
        minx 
<?= x[i];
        miny 
<?= y[i];
        maxx 
>?= x[i];
        maxy 
>?= y[i];
    }

    fx[minx].dist 
= 0;
    fx[minx].coor 
= minx;
    
for (int i = minx + 1; i <= maxx; i++)
        fx[minx].dist 
+= abs(i - minx) * hx[i];
    
int numrx = n - hx[minx];
    
int nummx = hx[minx];
    
int numlx = 0;
    
for (int i = minx + 1; i <= maxx; i++)
    
{
        fx[i].dist 
= fx[i - 1].dist + numlx + nummx - numrx;
        fx[i].coor 
= i;
        numlx 
+= nummx;
        nummx 
= hx[i];
        numrx 
-= nummx;
    }

    fy[miny].dist 
= 0;
    fy[miny].coor 
= miny;
    
for (int i = miny + 1; i <= maxy; i++)
        fy[miny].dist 
+= abs(i - miny) * hy[i];
    
int numry = n - hy[miny];
    
int nummy = hy[miny];
    
int numly = 0;
    
for (int i = miny + 1; i <= maxy; i++)
    
{
        fy[i].dist 
= fy[i - 1].dist + numly + nummy - numry;
        fy[i].coor 
= i;
        numly 
+= nummy;
        nummy 
= hy[i];
        numry 
-= nummy;
    }

    
for (int i = 0; i < n; i++)
        dd[i] 
= fx[x[i]].dist + fy[y[i]].dist;

    sort(fx 
+ minx, fx + maxx + 1);
    sort(fy 
+ miny, fy + maxy + 1);
    
int ans1;
    
for (int i = minx; i <= maxx; i++)
        
for (int j = miny; j <= maxy; j++)
        
{
            
if (ptrset.count(make_pair(fx[i].coor, fy[j].coor)) == 0)
            
{
                ans1 
= fx[i].dist + fy[j].dist;
                
goto end;
            }

        }

    end:;
    lnx 
= 0;
    
for (int i = minx; i <= maxx; i++)
    
{
        
if (i == minx)
        
{
            nx[lnx].dist 
= fx[i].dist;
            nx[lnx].num 
= 1;
            lnx
++;
        }

        
else
        
{
            
if (fx[i].dist == nx[lnx - 1].dist)
                nx[lnx 
- 1].num++;
            
else
            
{
                nx[lnx].dist 
= fx[i].dist;
                nx[lnx].num 
= 1;
                lnx
++;
            }

        }

    }


    lny 
= 0;
    
for (int i = miny; i <= maxy; i++)
    
{
        
if (i == miny)
        
{
            ny[lny].dist 
= fy[i].dist;
            ny[lny].num 
= 1;
            lny
++;
        }

        
else
        
{
            
if (fy[i].dist == ny[lny - 1].dist)
                ny[lny 
- 1].num++;
            
else
            
{
                ny[lny].dist 
= fy[i].dist;
                ny[lny].num 
= 1;
                lny
++;
            }

        }

    }

    
int ans2 = 0;
    
for (int i = 0; i < lnx; i++)
        
if (nx[i].dist <= ans1)
        
{
            
for (int j = 0; j < lny; j++)
                
if (nx[i].dist + ny[j].dist <= ans1)
                
{
                    
if (nx[i].dist + ny[j].dist == ans1)
                        ans2 
+= nx[i].num * ny[j].num;
                }

                
else break;
        }

        
else break;
    
for (int i = 0; i < n; i++)
        
if (dd[i] == ans1)
            ans2
--;
    printf(
"%d %d\n", ans1, ans2);
    
return 0;
}

posted on 2008-01-20 11:22 Felicia 阅读(1266) 评论(3)  编辑 收藏 引用 所属分类: 杂题
Comments
  • # re: [杂题]pku3269 曼哈顿距离的性质
    richardxx
    Posted @ 2008-02-01 23:08
    做了做,那个不相邻的条件的确是可以利用的。。
      回复  更多评论   
  • # re: [杂题]pku3269 曼哈顿距离的性质[未登录]
    Felicia
    Posted @ 2008-02-03 15:55
    @richardxx
    怎么用?请赐教  回复  更多评论   
  • # re: [杂题]pku3269 曼哈顿距离的性质
    richardxx
    Posted @ 2008-02-03 21:21
    分别求出x和y取最优的区间[L,R],[B,U]和最优值optx,opty,num = (R-L+1)*(U-B+1)-区域中的点,值是optx+opty.

    因为没有邻点,所以num = 0 iif L=R && B=U,而此时可知(L,B)这点四周都是空的,而新的最优值就是它们中的某些了。。
      回复  更多评论   

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理