Uva11134 Fabled Rooks【问题分解+贪心】【例题8-4】

题目: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;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值