Codechef SHOOTING

題目

10組數據。
每組數據:一個nmn*m的方陣,每個點上要麼有敵人,要麼有炮臺。
每個炮臺只能夠選擇上,左,右三個方向中的一個。該方向上所有的敵人都被消滅。
問是否存在一種方案,使得所有的敵人被消滅。
數據範圍:
T<=10,n,m<=50,L<=16T<=10,n,m<=50,L<=16
L表示炮臺的個數。

題解

三個套路:
降底數,和普通的貪心。
bitset優化
考慮狀壓,3163^{16}很大,再乘個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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章