Codechef SHOOTING

题目

10组数据。
每组数据:一个 n ∗ m n*m nm的方阵,每个点上要么有敌人,要么有炮台。
每个炮台只能够选择上,左,右三个方向中的一个。该方向上所有的敌人都被消灭。
问是否存在一种方案,使得所有的敌人被消灭。
数据范围:
T &lt; = 10 , n , m &lt; = 50 , L &lt; = 16 T&lt;=10,n,m&lt;=50,L&lt;=16 T<=10,n,m<=50,L<=16
L表示炮台的个数。

题解

三个套路:
降底数,和普通的贪心。
bitset优化
考虑状压, 3 16 3^{16} 316很大,再乘个10跑不过。
考虑将3变成2.
如果每个炮台只能选择左,右两个方向,那么怎么消灭所有的敌人?
显然,如果一行里有两个炮台,那么这行的敌人全能被消灭。
如果只有1个炮台,且它在这行的最边上,那么这行的敌人也全能被消灭。
因此,枚举哪个炮台选择上的方向,哪些不选择即可。
bitset维护敌人位置,左右方向的炮台的位置。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<bitset>
#define N 52
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int i,j,k,l,n,m,s,gs,sht,res;
int X[N],Y[N];
int T,cs;
bitset<N>b[N],bt[N],b1[N],b2[N];
bitset<N>L[N],R[N],c1,c2;
int _2[N];
char ch;
bool ia;
int main(){
 scanf("%d",&T);
 _2[1]=1;
 fo(i,2,20)_2[i]=_2[i-1]<<1;
 fo(cs,1,T){
  scanf("%d%d",&n,&m);
  fo(i,1,n){
   b[i].reset(),b1[i].reset();
   L[i].reset(),R[i].reset();
  }
  sht=0;ch=0;
  ia=0;gs=0;
  fo(i,1,n)fo(j,1,m){
   ch=getchar();
   while((ch^'.')&&(ch^'E')&&(ch^'L'))ch=getchar();
   if(ch=='E'){
    b[i][j]=1;
    sht++;
   }
   if(ch=='L'){
    gs++;
    X[gs]=i;
    Y[gs]=j;
    b1[i][j]=1;
   }
  }
  fo(i,1,n){
   fo(j,1,i)L[i][j]=1;
   fo(j,i,n)R[i][j]=1;
  }
  fo(s,0,_2[gs+1]-1){
   ia=1;
   res=sht;
   fo(i,1,n)bt[i]=b[i],b2[i]=b1[i];
   fo(i,1,gs)if(s&_2[i]){
    b2[X[i]][Y[i]]=0;
    fo(j,1,X[i]-1){
     if(bt[j][Y[i]]==1){
      bt[j][Y[i]]=0;
     }
    }
   }
   fo(i,1,gs)if(!(s&_2[i])){
    if(b2[X[i]].count()>=2){
     bt[X[i]].reset();
     continue;
    }
    c1=bt[X[i]]&L[Y[i]];
    c2=bt[X[i]]&R[Y[i]];
    if(c1.count()&&c2.count()){
     ia=0;
     break;
    }else bt[X[i]].reset();
   }
   fo(i,1,n){
    if(bt[i].count()){
     ia=0;
     break;
    }
   }
   if(ia)break;
  }
  if(ia)printf("Possible\n");else printf("Impossible\n");
 }
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值