【题目分析】
觉得是一道挺考验贪心掌握程度的题目,我就算知道是要用贪心而且肯定和区间有关,肯定要进行一下排序什么的我还是没有找到合适的贪心策略。
经过大佬的博客后我才明白如何进行贪心。
如果没有任何提示看这道题,首先,我们要有将复杂问题分解的能力,即这里要发现两个维度之间是没有什么关系的,所以可以分开进行然后在一起输出结果。
其次,我们要找到合适的贪心策略。正如大佬所说,贪心是问题导向的,我们不能盲目的排一下序然后试试,要观察问题想要的是什么。在这里,我们想要的是每个行(列也是相同的,这里就都当作行进行讨论)都有一个车。我们考虑从前往后放车,放哪个车比较合适呢?有很多车子的可行区间都包含这个点,我们要在这些车里面选择哪一个?直观上我们选取右区间最小的包含这个点的车最好(当然是没有被选过的)。想到这个策略需要一些灵感,而这个策略的正确性也是可以直观上感受的:从前往后我们每个格子选择的车都是右区间最小的,那么这就给后面的车留下了更多的可能性,总是最优的。
这里的车是一种必要的竞争关系,尽可能的减少对手就能够使后面的选择更加游刃有余,如果很多可以选择后面的车选择了前面,那么后面的行就面临没有车可以选的危险。
emmm,正确性应该也是可以证明的,但是想到这种贪心策略分析正确性的时候我们不会进行严格的数学证明(还是太笨,这样太慢太浪费时间),更多的是依靠直(xuan)觉(xue)。
【AC代码】
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<climits>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN=5e3+5;
int n;
struct node
{int l,r,idx;
}a1[MAXN],a2[MAXN];int vis[MAXN];int b1[MAXN],b2[MAXN];bool cmp(node &a,node &b)
{return a.r<b.r;
}int main()
{while(~scanf("%d",&n) && n){for(int i=1;i<=n;i++){scanf("%d%d%d%d",&a1[i].l,&a2[i].l,&a1[i].r,&a2[i].r);a1[i].idx=a2[i].idx=i;}sort(a1+1,a1+1+n,cmp);memset(vis,0,sizeof(vis));bool flag;for(int i=1;i<=n;i++){flag=false;for(int j=1;j<=n;j++){if(!vis[j] && a1[j].l<=i && a1[j].r>=i){vis[j]=true; b1[a1[j].idx]=i;flag=true;break;}}if(!flag) break;}if(!flag){printf("IMPOSSIBLE\n");continue;}sort(a2+1,a2+1+n,cmp);memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++){flag=false;for(int j=1;j<=n;j++){if(!vis[j] && a2[j].l<=i && a2[j].r>=i){vis[j]=true; b2[a2[j].idx]=i;flag=true;break;}}if(!flag) break;}if(!flag){printf("IMPOSSIBLE\n");continue;}for(int i=1;i<=n;i++){printf("%d %d\n",b1[i],b2[i]);}}return 0;
}