当前位置: 代码迷 >> 综合 >> UVA 11134 Fabled Rooks(贪心法,区间与选点问题)
  详细解决方案

UVA 11134 Fabled Rooks(贪心法,区间与选点问题)

热度:105   发布时间:2023-09-23 09:40:08.0

x轴,y轴不相关,所以分开考虑

贪心法  可以这样思考,不同于定区间选点,而是定点选区间,那么怎么对区间排序最优?

假设前提是从1开始取点放,对于其中x这个点,假设有很多区间[a,b]包含x这个点,那么对于那么多的区间我们只要选取b最小的就好,注意是在包含x的区间中选!!

但为了加快选中的概率,再加一条规则:b相同时取a最小的区间,毕竟区间越长包含x的概率大;

再理一遍:

1) b最小 : 因为1~x-1都是放好了的已经,而x+1~n还未放位置,所以我们要给后来的多多留位置; 

2)b相同时取a最小的区间 :对于b相同,相比更长的区间覆盖到x的几率更大,所以我们要排在前面;

综上[a,b]区间要按b优先排序,b相同时a取小;

另外,因为是从1开始放点,如果出现一个区间a<x&& b<x,肯定是问题无解的,因为前1~x-1的点还没选走这个区间,那么以后肯定没有任何一个点能放在这个区间。

比如说 [1,1],[2,2],[1,3]  按a大小排序[1,1],[1,3],[2,2] 是错误的而按b大小排序[1,1],[2,2], [1,3]才是对的

代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<numeric>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<ctime>
using namespace std;
const int maxn=5000+5;
int n,x1[maxn],x2[maxn],y1[maxn],y2[maxn],x[maxn],y[maxn];bool solve(int* a,int *b,int* c)   //[a,b] 
{memset(c,-1,sizeof(int)*n);  //  a[i] <= col <= b[i]/*fill(c,c+n,-1)  是对每一个int大小内存块初始化,而memset是对每个字节*/ for(int col=1;col<=n0;col++)  //在1~n给每个区间放个root {int root=-1,minb=n+1;for(int i=0;i<n;i++)if(c[i]<0&&a[i]<=col&& b[i]<minb) root=i,minb=b[i];//对于每个未放的区间选b最小的if(root<0||minb<col) return false;//if(放不了了||col为要放的位置>b即col在区间[a,b]外)   c[root]=col;}return true;
}int main()
{while(scanf("%d",&n)==1&&n){for(int i=0;i<n;i++)scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);if(solve(x1,x2,x)&&solve(y1,y2,y))for(int i=0;i<n;i++) printf("%d %d\n",x[i],y[i]);else printf("IMPOSSIBLE\n");}
}



优化一下,直接按上述规则排序后再选区间,更加省时间;

RunTime :从140ms到20ms

#include<iostream>
#include<vector>
#include<queue>
#include<numeric>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<ctime>
using namespace std;
const int maxn=5000+5;
int n,x[maxn],y[maxn];
struct point
{int a,b,p;  //[a,b]   第p个点要放置的区间 
}x1[maxn],y1[maxn];bool cmp(const point& a,const point& b)
{if(a.b!=b.b) return a.b<b.b;else return a.a<b.a;
}bool solve(point* x,int* c)   
{sort(x,x+n,cmp);memset(c,-1,sizeof(int)*n);  for(int col=1;col<=n;col++) {int root=-1,b=n+1;for(int i=0;i<n;i++)if(c[x[i].p]<0&&x[i].a<=col) {root=i,b=x[i].b;break;}if(root<0||b<col) return false;c[x[root].p]=col;}return true;
}int main()
{while(scanf("%d",&n)==1&&n){for(int i=0;i<n;i++)scanf("%d%d%d%d",&x1[i].a,&y1[i].a,&x1[i].b,&y1[i].b),x1[i].p=y1[i].p=i;if(solve(x1,x)&&solve(y1,y))for(int i=0;i<n;i++) printf("%d %d\n",x[i],y[i]);else printf("IMPOSSIBLE\n");}
}