例题8-4 传说中的车 UVa11134

1.题目描述:点击打开链接

2.解题思路:这道题利用贪心法,由于横坐标和纵坐标没有任何关系,因此可以分别处理。对于横坐标或纵坐标,贪心策略是:先按照区间右端点从小到大排序,若相同,再按照区间左端点从大到小排序,保证这种情况下长度短的在前,长的在后;每次都从区间的左端点出发,如果该位置已经被占据,则继续向后移动,如果移动到超出了区间右端点,则无解。(这道题我思考了三个贪心策略,第一个是按照右端点从小到大排序,然后每次都记录已经占据的位置的最大值,显然这是有漏洞的,因为中间可能有些位置是空的却被浪费了;第二种是按照左端点从小到大排序,如果相同,则按照右端点从小到大排序,每次从区间左端点出发,若已经被占据,则向后移,但这也是有漏洞的,因为你可能会导致左端点大但长度短的区间没有位置可以用;想到了长度,我的第三种策略则换成先按照长度由小到大排序,后面的做法和第二种完全一样,但不幸的是再次WA==,第三种策略的漏洞十分隐蔽,虽然你先解决了短区间的位置,但若干个短区间可能会把后面的长区间的位置给全部覆盖,导致错误结果。其实到这里,只要把这个问题解决,整道题就能AC了。解决的办法就是利用右端点从小到大排序隐含地相当于按照了长度从小到大排序,因为右端点限制了区间的最大允许长度,若右端点相同,则令左端点从大到小排序则隐含地实现了区间长度由小到大排序,这样,就不会出现小区间联合起来围堵大区间的情况了)

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
using namespace std;

const int maxn = 5000 + 10;
int x[maxn], y[maxn];
int n;
int visx[maxn],visy[maxn];//标记已经占据的位置
struct node
{
	int id;
	int xl, yl;
	int xr, yr;
}p[maxn];
bool cmp1(node s,node t)
{
	return (s.xr < t.xr || (s.xr == t.xr&&s.xl > t.xl));//先按照右端点从小到大排序,若相同,再按照左端点从大到小排序,此时保证短的在前面,长的在后面
}
bool cmp2(node s, node t)
{
	return (s.yr < t.yr || (s.yr == t.yr&&s.yl > t.yl));
}
int main()
{
	//freopen("test.txt", "r", stdin);
	while (scanf("%d", &n) && n)
	{
		int ok = 1;
		memset(p, 0, sizeof(p));
		memset(x, 0, sizeof(x));
		memset(y, 0, sizeof(y));
		memset(visx, 0, sizeof(visx));
		memset(visy, 0, sizeof(visy));
		for (int i = 0; i < n; i++)
		{
			scanf("%d%d%d%d", &p[i].xl, &p[i].yl, &p[i].xr, &p[i].yr);
			p[i].id = i + 1;
		}
		stable_sort(p, p + n, cmp1);
		if (n>1)
		{
			for (int i = 0; i < n; i++)
			{
				x[p[i].id] = p[i].xl;//贪心选择:总是从最左端开始
				while (visx[x[p[i].id]])//若已经用过,往后移
					x[p[i].id]++;
				visx[x[p[i].id]] = 1;
				if (x[p[i].id]>p[i].xr){ ok = 0; break; }//若超出了区间最右端,无解
			}
			if (ok)
			{
				stable_sort(p, p + n, cmp2);
				for (int i = 0; i < n; i++)
				{
					y[p[i].id] = p[i].yl;
					while (visy[y[p[i].id]])
						y[p[i].id]++;
					visy[y[p[i].id]] = 1;
					if (y[p[i].id]>p[i].yr){ ok = 0; break; }
				}
			}
		}
		if (n == 1)
		{
			x[1] = p[0].xl;
			y[1] = p[0].yl;
		}
		if (ok)
		for (int i = 1; i <= n; i++)
			printf("%d %d\n", x[i], y[i]);
		else printf("IMPOSSIBLE\n");
	}
	return 0;
}


参考代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
//#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

bool solve(int*a,int*b,int*c,int n)//解决一维的问题:找一个c,使得a[i]<=c[i]<=b[i]
{
    fill(c,c+n,-1);
    for(int col=1;col<=n;col++)
    {
        int rook=-1,minb=n+1;
        for(int i=0;i<n;i++)
            if(c[i]<0&&b[i]<minb&&col>=a[i])//找一个没有安排过的车,它的b[i]最小
        {
            rook=i;minb=b[i];
        }
        if(rook<0||col>minb)return false; //如果没有找到,或者虽然找到了,但是最大范围小于col,则无解
        c[rook]=col;
    }
    return true;
}

const int N=5000+5;
int n,x1[N],y1[N],x2[N],y2[N],x[N],y[N];

int main()
{
    while(~scanf("%d",&n)&&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,n)&&solve(y1,y2,y,n))//两个一维的问题都解决了,那么本题就有解
            for(int i=0;i<n;i++)
            printf("%d %d\n",x[i],y[i]);
        else puts("IMPOSSIBLE");
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值