• 安全逃离的题解


    也农夫john最近在研究如果发生重大事故,如何让农场里的奶牛逃离问题。他想要确信在紧急情况下,所有的奶牛都有一个安全逃离方案。因为在紧急情况下,奶牛们都会失去观察和判断能力,所以最近john一直在教奶牛们逃离的方法,他的方法很简单,就是任何时候都只向北方或东方逃离,北方是行坐标减1的方向,东方是列坐标加1的方向。奶牛们虽笨,不过这一点事关自己的生命,所以他们牢记在心,而且也一定会这么做。
    当然也会出问题,奶牛们在逃离的方向上会横冲直撞,为了阻止奶牛之间互相冲撞造成伤害,john要求任何一个奶牛的逃离路线不能经过其它奶牛的初始位置。一个逃离方案是安全的如果它能够满足上面的要求,反之它就是不安全的。
    奶牛们所在的土地(农场)被划分成了r行和c列的一个矩形地图。奶牛们都待在这个矩形中的某一个位置。
    请帮助john确定给定的一个地图上是否存在一个安全的逃离方案。
    比如,下面的两个图:
    左边的例子表示了一个能够安全逃离的地图,因为没有任何一个奶牛的逃离路线上包括其他奶牛。右边的例子表示了一个不安全的地图,因为位于(4,1)的奶牛不论是向东逃离还是向北逃离,它的路线上都会有别的奶牛,从这个图中拿掉任意一头奶牛,这个地图都会变成安全的。

          安全               不安全
      | | | | C--         C . . . . . 
      | | | | C--         ^ . . . . . 
      | C | | C--         | . . . . . 
      C C-+-+----         C------>C . 
      . . C C C--         . . . . . . 
    

    C表示奶牛,直线表示逃离路线

    错点

    蒟蒻向老师报告题目有问题后没有认真看题,结果就死了。

    分析

    做到这道题的时候,我们考到数据范围很小,考虑高复杂度的做法。

    我的做法是最暴力的做法,复杂度大概是 O(cr2×+rc2×n)O(cr^2 imes + rc^2 imes n),面对这么小的这么小的数据,这个做法显然能过。

    我们先写一个 checkcheck 函数,判断此时的矩阵是否安全。

    bool check(){
        for(int i=1;i<=r;++)
            for(int j=1;j<=c;j++)
                if(a[i][j]){//此点有牛
                    int s=0;
                    for(int l=1;l<=i;l++)
                        if(a[l][j]){
                            s++;
                            break;
                        }
                    for(int l=j;l<=n;l++)
                        if(a[i][l]){
                            s++;
                            break;
                        }
                    if(s==2)return false;//如果有牛上面和右面都被堵死了,这个矩阵显然是不安全的
                }
        return true;
    }
    

    当然还有更快速地写法啦

    bool save(){
    	for(int i=1;i<=k;i++){
    		int flag=0;
    		for(int l=x[i]-1;l>=1;l--)
    			if(a[l][y[i]]){
    				flag++;
    				break;
    			}
    		for(int l=y[i]+1;l<=n;l++)
    			if(a[x[i]][l]){
    				flag++;
    				break;
    			}
    		if(flag==2)return false;
    	}
    	return true;
    }
    

    我们再写一个函数去枚举移掉哪头牛

    void work(){
    	int f=1;
    	for(int i=1;i<=k;i++){
    		a[x[i]][y[i]]--;
    		if(save()){//如果安全
    			f=0;
    			write(i);//输出
    			puts("");
    		}
    		a[x[i]][y[i]]++;
    	}if(f)puts("-1");//无解
    }
    

    总代码

    #include <bits/stdc++.h>
    using namespace std;
    template<typename T>inline void read(T &FF){
    	T RR=1;FF=0;char CH=getchar();
    	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    	FF*=RR;
    }
    template<typename T>void write(T x){
    	if(x<0)putchar('-'),x*=-1;
    	if(x>9)write(x/10);
    	putchar(x%10+48);
    }
    const int MAXN=50+10,MAXK=100+10;
    int a[MAXN][MAXN],n,m,k,x[MAXK],y[MAXK];
    bool save(){
    	for(int i=1;i<=k;i++){
    		int flag=0;
    		for(int l=x[i]-1;l>=1;l--)
    			if(a[l][y[i]]){
    				flag++;
    				break;
    			}
    		for(int l=y[i]+1;l<=n;l++)
    			if(a[x[i]][l]){
    				flag++;
    				break;
    			}
    		if(flag==2)return false;
    	}
    	return true;
    }
    void work(){
    	int f=1;
    	for(int i=1;i<=k;i++){
    		a[x[i]][y[i]]--;//移除
    		if(save()){
    			f=0;
    			write(i);
    			puts("");
    		}
    		a[x[i]][y[i]]++;//注意回溯
    	}if(f)puts("-1");
    }
    int main(){
    	read(n);read(m);read(k);
    	for(int i=1;i<=k;i++){
    		read(x[i]);read(y[i]);
    		a[x[i]][y[i]]++;
    	}
    	if(save())puts("0");
    	else work();
    	return 0;
    }
    
  • 相关阅读:
    哲学家进餐
    文件系统
    文件读写原理(转)
    数据库join种类
    http与https区别
    数字证书(转)
    B. Rebranding
    扩展欧几里德算法、证明及其应用
    CodeForces 7C Line
    UVALive 7147 World Cup
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12816947.html
Copyright © 2020-2023  润新知