CF 254D Rats(枚举+bfs+各种乱搞)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给出一个地图,某些位置有一些老鼠,有两个炸弹,攻击范围每一秒都能向4个方向扩散,不能穿过墙。炸弹会在d秒后爆炸,问是否能找到两个位置,放置炸弹,能炸死所有老鼠(= = 大概意思就这样
首先把所有的R找出来,可以通过R的个数剪枝一次。
我们可以发现d其实是很小的,也许这是一个突破口吧
每一个炸弹极限情况下能在d秒扩散的范围是可以算出来,就是一个菱形的东东吧。
那么两个炸弹最多覆盖的范围也可以算出来,这里可以 小剪一下。对于R很多的情况,直接pass掉了,good
那么再考虑可行的范围,一个炸弹能到达的位置,肯定是曼哈顿距离小于d
以每只老鼠为中心,先把所有可行的点拿出来(= =至少得覆盖一只老鼠才会开始考虑吧
其实这里也是可以剪枝一下的,我们考虑当一个炸弹扩散,最极端的情况是,最外面一圈是炸弹,然后再用最外面一圈去扩散,相当于炸弹扩散2*d次,可以算出最多有多少个位置可行,那么如果可行的位置过多,说明老鼠过于分散,也是不可行。
然后对于可行解去BFS,记录能到达哪些老鼠,对于每一个可能的可行解都用set记录了到达的老鼠标号。
最后两两枚举,合并set,判断是否能搞定所有老鼠。
TLE了好久,加上一个小剪枝就过了,果然是合并set太矬了
其实复杂度是可行的
BFS的状态数目最多大概为226吧,那个可能可行解上限大概是1200左右
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#include<string>  
#include<queue>  
#define inf 1600005  
#define M 40  
#define N 1005
#define maxn 2000005  
#define eps 1e-7
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");  
#define pi acos(-1.0)
#define lowbit(x) ((x)&(-(x)))
#pragma comment(linker, "/STACK:1024000000,1024000000")  
#define vi vector<int> 
using namespace std;
int row,col,d;
char str[N][N];
vector<pair<int,int> >rat,tmp;
int p[N][N];
set<int>s[N];
int way[4][2]={0,1,0,-1,1,0,-1,0};
bool flag[N][N];
bool check(int x,int y){
    if(x>=0&&y>=0&&x<row&&y<col&&str[x][y]!='X')
        return true;
    return false;
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    while(scanf("%d%d%d",&row,&col,&d)!=EOF){
        rat.clear();mem(p,-1);
        for(int i=0;i<row;i++){
            scanf("%s",str[i]);
            for(int j=0;j<col;j++)
                if(str[i][j]=='R'){
                    rat.pb(mp(i,j));
                    p[i][j]=rat.size();
                }
        }
        //剪枝,两个位置,扩展d次,可以算出最多覆盖多少个格子
        int t=d+1;
        if(rat.size()>2*(2*sqr(t)-2*t+1)){
            puts("-1");
            continue;
        }
        for(int i=0;i<rat.size();i++){
            for(int j=-d;j<=d;j++){
                for(int k=-d;k<=d;k++){
                    if(abs(j)+abs(k)>d) continue;
                    int x=rat[i].first+j;
                    int y=rat[i].second+k;
                    if(check(x,y)) tmp.pb(mp(x,y));
                }
            }
        }
        sort(tmp.begin(), tmp.end());
        int size=unique(tmp.begin(), tmp.end())-tmp.begin();
        t*=2;
        if(size> 2*(2*sqr(t)-2*t+1) ){
            puts("-1");
            continue;
        }
        for(int i=0;i<size;i++){
            queue<pair<pair<int,int>,int> >que;
            while(!que.empty()) que.pop();
            mem(flag,false);
            flag[tmp[i].first][tmp[i].second]=true;
            que.push(mp(mp(tmp[i].first,tmp[i].second),0));
            while(!que.empty()){
                pair<pair<int,int>,int>u=que.front(),v;
                que.pop();
                if(str[u.first.first][u.first.second]=='R')
                    s[i].insert(p[u.first.first][u.first.second]);
                if(u.second>=d) continue;
                for(int i=0;i<4;i++){
                    v=u;
                    v.first.first+=way[i][0];
                    v.first.second+=way[i][1];
                    v.second+=1;
                    if(check(v.first.first,v.first.second)&&!flag[v.first.first][v.first.second]){
                        flag[v.first.first][v.first.second]=true;
                        que.push(v);
                    }
                }
            }
        }
        bool ans=false;
        for(int i=0;i<size&&!ans;i++){
            for(int j=i+1;j<size&&!ans;j++){
                //唔,这个剪枝,直接从T到100ms,果然我乱用set太慢了
                if(s[i].size()+s[j].size()<rat.size()) continue;
                set<int>temp(s[i]);
                for(set<int>::iterator it=s[j].begin();it!=s[j].end();it++)
                    temp.insert(*it);
                if(temp.size()==rat.size()){
                    ans=true;
                    printf("%d %d %d %d\n",tmp[i].first+1,tmp[i].second+1,tmp[j].first+1,tmp[j].second+1);
                }
            }
        }
        if(!ans) puts("-1");
        for(int i=0;i<size;i++) s[i].clear();
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值