ZOJ 3041 City Selection(二维比较,排序分析)
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3041
题意:
现在有m个工厂和n个打算建城市的地点(给出所有点的x和y坐标,且(0,0)位于2维坐标轴的中心),如果有一个工厂在一个打算建城市地点的左上角(就算在边界也算),那么该地点就不能建城市(因为会被污染).现在要你输出所有可以建城市的点坐标.
分析:
如果有工厂 x 坐标 <= 城市 x 坐标且工厂 y 坐标 >= 城市 y 坐标,那么该城市点不可行.(其实就是看该城市点的左上角是否有一个工厂点)
问题1:如果我们想知道点i(xi,yi)是否可建城市,我们需要怎么做?
只要看二维坐标轴上,在点 i 的左边是否有一个工厂点的 y 坐标 >= yi 即可。
问题2:如何快速的确定所有的城市点是否可行?
我们通过将所有工厂和城市点按x从小到大,(如果x相等,则y从大到小,如果x和y都相等,就把工厂排在城市前面)的顺序排序.
现在我们确定了x坐标一定是从小到大排序的,所以如果我们当前考虑第i个点(该点是城市)是否可行时?我们只要从0到i-1这些点中找出是否有一个工厂的y坐标大于等于它的y坐标就行(因为这前面任意工厂的x坐标肯定<=该地点的x坐标).
所以程序中我们用y来记录我们当前所遇到过的所有工厂中y坐标的最大值.如果这个最大值依然小于当前城市点的y坐标,那么就不可能有妨碍该城市的工厂存在了.(因为只有城市点左边的工厂才可能妨碍该点建立城市,自己想想是不是)
AC代码(新):
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
struct Node
{
int x;
int y;
bool f;//ture时表示工厂factory
Node(int x,int y,bool f):x(x),y(y),f(f){}
bool operator<(const Node &rhs)const
{
return x<rhs.x || (x==rhs.x && y<rhs.y);
}
};
bool cmp(const Node &lhs,const Node &rhs)
{
return lhs.x<rhs.x || (lhs.x==rhs.x && lhs.y>rhs.y)
|| (lhs.x==rhs.x && lhs.y==rhs.y && lhs.f);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
//所有点都保存在vc1中
vector<Node> vc1;
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vc1.push_back(Node(x,y,false));
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vc1.push_back(Node(x,y,true));
}
sort(vc1.begin(),vc1.end(),cmp);
//vc2中只保存可建城市的点
vector<Node> vc2;
int max_y=-1e9-1;//当前最大的y坐标
for(int i=0;i<vc1.size();i++)
{
if(vc1[i].f==true)//工厂点
{
max_y=max(max_y, vc1[i].y);
}
else//城市点
{
if(vc1[i].y > max_y) vc2.push_back(vc1[i]);
}
}
sort(vc2.begin(),vc2.end());
printf("%d\n",vc2.size());
for(int i=0;i<vc2.size();i++)
printf("%d %d\n", vc2[i].x, vc2[i].y);
}
}
AC代码:
虽然本代码能AC,但是是错的。对于下列数据:
3 3 0 1 -2 1 1 3 -2 2 2 0 4 4会得到错误的输出:
2
-2 1
1 3
正确的输出应该是:
1
1 3
原因在于代码中按x从小到大,y从小到大,工厂优先排序的。应该按x从小到大,y从大到小,工厂优先排序。因为当两个点x坐标相同时,我们应该优先考虑y坐标大的点更新当前工厂最大y值。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 2e10
const int maxn=200000*2+10;
struct Node
{
int x,y;
bool f;//true时表工厂
bool operator<(const Node& rhs)const
{
return x<rhs.x ||(x==rhs.x && y<rhs.y)||(x==rhs.x && y==rhs.y && f);
}
}nodes[maxn];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
for(int i=0;i<n;++i)
{
scanf("%d%d",&nodes[i].x,&nodes[i].y);
nodes[i].f=false;
}
for(int i=n;i<n+m;++i)
{
scanf("%d%d",&nodes[i].x,&nodes[i].y);
nodes[i].f=true;
}
sort(nodes,nodes+n+m);
int ans=0;//最终能建city的地方数目
int num[maxn];
int y=-INF;//之前所有工厂中,y的最大值
for(int i=0;i<n+m;++i)
{
if(nodes[i].f==true)//工厂
y=max(y,nodes[i].y);
else //城市
{
if(y<nodes[i].y)//可建城市
num[ans++]=i;
}
}
printf("%d\n",ans);
for(int i=0;i<ans;++i)
printf("%d %d\n",nodes[num[i]].x,nodes[num[i]].y);
}
return 0;
}