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; }