也农夫john最近在研究如果发生重大事故,如何让农场里的奶牛逃离问题。他想要确信在紧急情况下,所有的奶牛都有一个安全逃离方案。因为在紧急情况下,奶牛们都会失去观察和判断能力,所以最近john一直在教奶牛们逃离的方法,他的方法很简单,就是任何时候都只向北方或东方逃离,北方是行坐标减1的方向,东方是列坐标加1的方向。奶牛们虽笨,不过这一点事关自己的生命,所以他们牢记在心,而且也一定会这么做。
当然也会出问题,奶牛们在逃离的方向上会横冲直撞,为了阻止奶牛之间互相冲撞造成伤害,john要求任何一个奶牛的逃离路线不能经过其它奶牛的初始位置。一个逃离方案是安全的如果它能够满足上面的要求,反之它就是不安全的。
奶牛们所在的土地(农场)被划分成了r行和c列的一个矩形地图。奶牛们都待在这个矩形中的某一个位置。
请帮助john确定给定的一个地图上是否存在一个安全的逃离方案。
比如,下面的两个图:
左边的例子表示了一个能够安全逃离的地图,因为没有任何一个奶牛的逃离路线上包括其他奶牛。右边的例子表示了一个不安全的地图,因为位于(4,1)的奶牛不论是向东逃离还是向北逃离,它的路线上都会有别的奶牛,从这个图中拿掉任意一头奶牛,这个地图都会变成安全的。安全 不安全 | | | | C-- C . . . . . | | | | C-- ^ . . . . . | C | | C-- | . . . . . C C-+-+---- C------>C . . . C C C-- . . . . . .
C表示奶牛,直线表示逃离路线
错点
蒟蒻向老师报告题目有问题后没有认真看题,结果就死了。
分析
做到这道题的时候,我们考到数据范围很小,考虑高复杂度的做法。
我的做法是最暴力的做法,复杂度大概是 ,面对这么小的这么小的数据,这个做法显然能过。
我们先写一个 函数,判断此时的矩阵是否安全。
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;
}