题目:Fabled Rooks
题意:在一个n*n的棋盘中放n辆车,这n辆车不互相攻击(即不同行和列);给出第i辆的停车范围(xli,yli),(xri,yri) ,输出i辆车的停车坐标,如果无解输出IMPOSSIBLE 。
思路:因为是行和列不互相攻击,所有我们可以分解成将俩个一维数组求,即求i辆车的横坐标,其范围为(xli,xri) ;求i辆车的纵坐标,其范围为(yli,yri)。
怎么求这个位置呢?我开始给拍了个序,求出后WA啦,估计是漏掉了值。后参考了代码库。
(1)用一个新数组来存放最后的坐标值,首先将其置0;
(2)然后枚举第i车的坐标(横或列)就是数字i,只不过在寻找它应放到给出的哪个位置合适。再用一循环判断当前i是否在范围内,且在范围内的情况下寻找最小的右边界点,且当前点是没有访问过的(即0)。
(3)然后判断得出的右边界是否符合当前的i值,符合的话将记录下来的下标值和当前的i分别放入数组中,否则退出,即无解!
(4)当横和列都符合以上后输出解。
注意:在函数中将传入的数组置0需要用fill() 使用memset()无效!
参考:紫书-例8-4-P237 + 代码库
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 5000 + 5;
struct position{
int s,t;
};
bool solve(int n,position v[],int p[]){
//memset(p,0,sizeof(p));//先将数组标记为0
fill(p,p+n,0);//先将数组标记为0,注意将传入的数组置0需用fill,用memset无效!
for(int i=1;i<=n;i++){
int mint = n+1,index = -1;
for(int j=0;j<n;j++)
if(!p[j] && i >= v[j].s && v[j].t < mint){//i在范围内,且取右范围最靠前的
mint = v[j].t;//保存较小的右范围
index = j;//记录是第几个的范围
}
if(i > mint || index == -1) return false;//当前坐标已经超出右范围,或者没有符合的范围就无法停车了
p[index] = i;//将当前坐标放入相应的范围内
}
return true;
}
int main()
{
int n;
int px[maxn],py[maxn];
position x[maxn],y[maxn];
while(~scanf("%d",&n) && n){
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&x[i].s,&y[i].s,&x[i].t,&y[i].t);
if(solve(n,x,px) && solve(n,y,py))//当都停放成功时
for(int i=0;i<n;i++) printf("%d %d\n",px[i],py[i]);
else printf("IMPOSSIBLE\n");
}
return 0;
}