zoukankan      html  css  js  c++  java
  • 【HDU

    Descriptions:

    一个人从(0,0)跑到(n,m),只有k点能量,一秒消耗一点,在图中有k个炮塔,给出炮塔的射击方向c,射击间隔t,子弹速度v,坐标x,y
    问这个人能不能安全到达终点
    要求:
    1.人不能到达炮塔所在的坐标
    2.炮塔会挡住子弹
    3.途中遇到子弹是安全的,但是人如果停在这个坐标,而子弹也刚好到这个坐标,人就被射死
    4.人可以选择停止不动

    Input

    对于每个测试用例,第一行有四个整数,m、n、k和d (2<=m, n<=100, 0<=k<=100, m+ n<=d<=1000)。m和n是战场的大小,k是城堡的数量,d是A最初拥有的能量单位。接下来的k行分别描述了这些城堡。每一行包含一个字符c和四个整数,t, v, x和y。c是“N”,“S”,“E”或“W”给城堡的发射方向,t, v是子弹的速度(即单位通过每秒),和(x, y)是城堡的位置。这里我们假设,如果一座城堡被其他城堡击中,它会挡住其他人的射击,但不会被摧毁。两颗子弹会在不影响它们的方向和速度的情况下擦肩而过。

    当小A开始逃跑时,所有的城堡都开始射击。

    继续到文件末尾。

    Output

    如果小A能逃跑,在一行中输入其所需的最小秒数。否则,在一行中输出"Bad luck!"(无需带引号)

    Sample Input

    4 4 3 10
    N 1 1 1 1
    W 1 1 3 2
    W 2 1 2 4
    4 4 3 10
    N 1 1 1 1
    W 1 1 3 2
    W 1 1 2 4
    

    Sample Output

    9
    Bad luck!
    

    坑点:炮台的位置是不能走的,不只是会0距离射击,而是那个位置根本不能去,题目没有表述清楚这一点。

    其实不难,我们只需要看当人位于某个点的时候,其四个方向是否有炮塔,这个炮塔是都向人的方向射击,然后再看子弹是否刚好位于这个坐标即可。

    而标记的话,book[x][y][time],对于time时刻,人位于x,y的情况只需要访问一次,这是唯一的

    #include<bits/stdc++.h>
    using namespace std;
    const int dx[] = { 1,-1,0,0,0 };
    const int dy[] = { 0,0,1,-1,0 };
    int n, m, k, hp;
    int map[105][105];
    bool book[105][105][105];
    
    struct period {
        char c; int t, v;
    }s[105][105];
    
    struct node {
        int x, y, step;
    };
    
    #define Check(x,y) ( x < 0 || x > n || y < 0 || y > m )
    
    void bfs()
    {
        node now, net;
        queue<node> q;
        int i, j, flag, dis, timee;
        now.x = now.y = now.step = 0;
        q.push(now);
        book[0][0][0] = true;
        while (!q.empty())
        {
            now = q.front();
            q.pop();
            if (now.step > hp)
                break;
            if (now.x == n && now.y == m)
            {
                cout << now.step << endl;
                return;
            }
            for (i = 0; i < 5; i++)
            {
                net = now;
                net.x += dx[i];
                net.y += dy[i];
                net.step++;
                if (Check(net.x, net.y))
                    continue;
                if (!s[net.x][net.y].t && !book[net.x][net.y][net.step] && net.step <= hp)//在符合条件的情况下,枚举四个方向
                {
                    flag = 1;
                    for (j = net.x - 1; j >= 0; j--)//当位于这点,我们往北向寻找是否有朝南方向射击的炮台
                    {
                        if (s[j][net.y].t && s[j][net.y].c == 'S')//找到第一个炮台,且这个炮台是朝南射击的
                        {
                            dis = net.x - j;//看炮台与人的距离
                            if (dis%s[j][net.y].v)
                                break;//因为不需要看子弹中途的点,子弹每一秒跑v,距离是dis,dis不能整除v的话,那么子弹是不可能停在这个点的
                            timee = net.step - dis / s[j][net.y].v;//人走的时间减去第一个子弹飞行到这个位置所需的时间
                            if (timee < 0)
                                break;//为负数就是第一个子弹都没有经过这个点,那么人绝对安全
                            if (timee%s[j][net.y].t == 0)//看间隔,能整除,那么就是后续有子弹刚好到这个点,人死定了
                            {
                                flag = 0;
                                break;
                            }
                        }
                        if (s[j][net.y].t)//找到炮台但不是朝南射击,那么这个炮台会当下后面所有子弹,所以北方向安全我们不需要再找
                            break;
                    }
                    if (!flag)//这个方向都死定了,后面也就不需要看了
                        continue;
                    //其他方向也是一样的道理,就不注释了
                    for (j = net.x + 1; j <= n; j++)
                    {
                        if (s[j][net.y].t && s[j][net.y].c == 'N')
                        {
                            dis = j - net.x;
                            if (dis%s[j][net.y].v)
                                break;
                            timee = net.step - dis / s[j][net.y].v;
                            if (timee < 0)
                                break;
                            if (timee%s[j][net.y].t == 0)
                            {
                                flag = 0;
                                break;
                            }
                        }
                        if (s[j][net.y].t)
                            break;
                    }
                    if (!flag)
                        continue;
                    for (j = net.y - 1; j >= 0; j--)
                    {
                        if (s[net.x][j].t && s[net.x][j].c == 'E')
                        {
                            dis = net.y - j;
                            if (dis%s[net.x][j].v)
                                break;
                            timee = net.step - dis / s[net.x][j].v;
                            if (timee < 0)
                                break;
                            if (timee%s[net.x][j].t == 0)
                            {
                                flag = 0;
                                break;
                            }
                        }
                        if (s[net.x][j].t)
                            break;
                    }
                    if (!flag)
                        continue;
                    for (j = net.y + 1; j <= m; j++)
                    {
                        if (s[net.x][j].t && s[net.x][j].c == 'W')
                        {
                            dis = j - net.y;
                            if (dis%s[net.x][j].v)
                                break;
                            timee = net.step - dis / s[net.x][j].v;
                            if (timee < 0)
                                break;
                            if (timee%s[net.x][j].t == 0)
                            {
                                flag = 0;
                                break;
                            }
                        }
                        if (s[net.x][j].t)
                            break;
                    }
                    if (!flag)
                        continue;
                    book[net.x][net.y][net.step] = true;
                    q.push(net);
                }
            }
        }
        cout << "Bad luck!" << endl;
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        while (cin >> n >> m >> k >> hp) {
            memset(book, false ,sizeof book);
            memset(s, false ,sizeof s);
            for (int i = 0; i < k; ++i) {
                char c; int t, v, x, y;
                cin >> c >> t >> v >> x >> y;
                s[x][y].c = c;
                s[x][y].t = t;
                s[x][y].v = v;
            }
            bfs();
        }
        return 0;
    }
    

    Astar解法( A*算法每次从 优先队列 中取出一个 最小的,然后更新相邻的状态。)

    用A*很合适,h估计距离可以直接用曼哈顿距离,并且保证一定比实际距离小,能保证寻到最优解。注意A*算法能找到最优解的充要条件是估计距离h小于等于实际距离,否则只能找到路径,但不一定是最短路,只能称作A算法。本题中,由于曼哈顿距离是当前位置到终点的最短路径,而实际情况只可能比这个路径长,因此一定可以找到最短距离解。

    路线上是否有子弹的计算:寻找四周指向当前位置的炮台(并且注意到一个炮台能挡住后面的子弹),计算到达当前位置的t0时间,即距离(dist/v),然后接下来就是周期t重复了,则看当前时间(tt==t0+t*k)是否成立,即((tt-t0)%t)是否为0。

    #include<bits/stdc++.h>
    using namespace std;
    
    int m, n, k, d;
    
    struct castle
    {
        char c;
        int t, v;
    } mp[105][105];
    
    bool vis[105][105][1005];
    
    void init()
    {
        memset(vis, false, sizeof vis);
        for (int i = 0; i <= m; i++)
        {
            for (int j = 0; j <= n; j++)
            {
                mp[i][j].t = 0;
                mp[i][j].v = 0;
            }
        }
    }
    
    struct node
    {
        int g, h, x, y;
        bool operator<(const node n1)const
        {
            return (n1.g + n1.h) < (g + h);
        }
    };
    
    
    int get_h(int x, int y)
    {
        return abs(x - m) + abs(y - n);
    }
    
    int dx[5] = { 0,0,-1,1,0 };
    int dy[5] = { -1,1,0,0,0 };
    
    int astar()
    {
        if (mp[0][0].t != 0) return -1;
        node e;
        e.g = 0;
        e.h = get_h(0, 0);
        e.x = 0;
        e.y = 0;
    
        priority_queue<node> pq;
        pq.push(e);
        vis[0][0][0] = true;
    
        while (!pq.empty())
        {
            node cur = pq.top();
            pq.pop();
            int x = cur.x;
            int y = cur.y;
    
            for (int i = 0; i < 5; i++)
            {
                int xx = x + dx[i];
                int yy = y + dy[i];
                if (xx<0 || xx>m || yy<0 || yy>n) continue;
    
                bool flag = false;
    
                node next = cur;
                next.g++;
                if (vis[xx][yy][next.g] == true) continue;
                if (mp[xx][yy].t) continue;
                if (xx == m && yy == n) return next.g;
    
                for (int cx = xx - 1; cx >= 0; cx--)
                {
                    if (mp[cx][yy].t != 0)
                    {
                        int L = xx - cx;
                        if (mp[cx][yy].c == 'S'&&L%mp[cx][yy].v == 0)
                        {
                            int t0 = L / mp[cx][yy].v;
                            int dt = next.g - t0;
                            if (dt >= 0 && (dt%mp[cx][yy].t == 0)) flag = true;
                        }
                        break;
                    }
                }
    
                for (int cx = xx + 1; cx <= m; cx++)
                {
                    if (mp[cx][yy].t != 0)
                    {
                        int L = cx - xx;
                        if (mp[cx][yy].c == 'N'&&L%mp[cx][yy].v == 0)
                        {
                            int t0 = L / mp[cx][yy].v;
                            int dt = next.g - t0;
                            if (dt >= 0 && (dt%mp[cx][yy].t == 0)) flag = true;
                        }
                        break;
                    }
                }
    
                for (int cy = yy - 1; cy >= 0; cy--)
                {
                    if (mp[xx][cy].t != 0)
                    {
                        int L = yy - cy;
                        if (mp[xx][cy].c == 'E'&&L%mp[xx][cy].v == 0)
                        {
                            int t0 = L / mp[xx][cy].v;
                            int dt = next.g - t0;
                            if (dt >= 0 && (dt%mp[xx][cy].t == 0)) flag = true;
                        }
                        break;
                    }
                }
    
                for (int cy = yy + 1; cy <= n; cy++)
                {
                    if (mp[xx][cy].t != 0)
                    {
                        int L = cy - yy;
                        if (mp[xx][cy].c == 'W'&&L%mp[xx][cy].v == 0)
                        {
                            int t0 = L / mp[xx][cy].v;
                            int dt = next.g - t0;
                            if (dt >= 0 && (dt%mp[xx][cy].t == 0)) flag = true;
                        }
                        break;
                    }
                }
    
                if (flag) continue;
                next.x = xx;
                next.y = yy;
                next.h = get_h(xx, yy);
                if ((next.g + next.h) > d) continue;
                pq.push(next);
                vis[xx][yy][next.g] = true;
            }
        }
    
        return -1;
    }
    
    int main()
    {
        freopen("in.txt", "r", stdin);
        while (scanf("%d%d%d%d", &m, &n, &k, &d) == 4)
        {
            init();
            char c;
            int t, v, x, y;
            getchar();
            for (int kk = 0; kk < k; kk++)
            {
                c = getchar();
                scanf("%d%d%d%d", &t, &v, &x, &y);
                getchar();
                mp[x][y].c = c;
                mp[x][y].t = t;
                mp[x][y].v = v;
            }
    
            int ret = astar();
    
            if (ret == -1) printf("Bad luck!
    ");
            else printf("%d
    ", ret);
        }
    
        return 0;
    }
    

    Time 从第一种方法的1762ms 降到了 234ms

    bfs + 预处理 + 剪枝

    #include<bits/stdc++.h>
    using namespace std;
    const int maxt=1000+10;
    const int maxn2=100+5;
    struct castle{       //碉堡节点 
    	int t,v,x,y;     //时间间隔、速度、坐标 
    	char c;
    	castle(int t=0,int v=0,int x=0,int y=0,char c='N'):t(t),v(v),x(x),y(y),c(c){}
    }cas[maxn2];
    struct node{
    	int x,y;
    	int time;   //走到当前节点花了多少时间 
    	node(int x=0,int y=0,int time=0):x(x),y(y),time(time){}
    };
    bool vis[maxt][maxn2][maxn2];  
    bool remb[maxt][maxn2][maxn2]; //记录每个时刻那些位置有炮弹 
    bool g[maxn2][maxn2];   //记录碉堡的坐标 
    int m,n,k,d;
    int dir[][2]={{1,0},{-1,0},{0,-1},{0,1},{0,0}};
    bool isValid(node &nd){
    	return nd.x>=0&&nd.x<=m && nd.y>=0&&nd.y<=n;
    }
    void solve(){
    	memset(remb,false,sizeof(remb));	
    	for(int i=0;i<k;i++){
    		int x=0,y=0;
    		switch(cas[i].c){
    			case 'N': x=-1;break;
    			case 'S': x=1;break;
    			case 'W': y=-1;break;
    			case 'E': y=1;
    		}
    		int x1,y1;
            for(int j=1;;j++){
            	x1=j*x+cas[i].x;   
            	y1=j*y+cas[i].y;
            	if(x1<0 || x1>m || y1<0 || y1>n)break;
            	if(g[x1][y1])break;            
            	if(j%cas[i].v==0){  //子弹会停留的坐标,时间=步数/速度 
            		for(int h=j/cas[i].v;h<=d;h+=cas[i].t){
            			remb[h][x1][y1]=true;
    				}
    			}
    		}
      }
    }
    bool judge(node &nd){   //当逃到某点时,明显无法到终点时,剪枝 
    	if(nd.time>d)return false;
    	int temp=abs(nd.x-m)+abs(nd.y-n);
    	return d-nd.time>=temp;
    }
    void bfs(){
    	memset(vis,false,sizeof(vis));
    	queue<node>q;
    	q.push(node(0,0,0));
    	vis[0][0][0]=true;
    	while(!q.empty()){
    		node u=q.front();
    		q.pop();
    		if(u.x==m && u.y==n){
    			printf("%d
    ",u.time);
    			return ;
    		}
    		for(int i=0;i<5;i++){
    			node v=node(u.x+dir[i][0],u.y+dir[i][1],u.time+1);
    			if(isValid(v) && !vis[v.time][v.x][v.y] && !remb[v.time][v.x][v.y] && judge(v) && !g[v.x][v.y]){
    				q.push(v);
    				vis[v.time][v.x][v.y]=true;
    			}
    		}
    	}
    	printf("Bad luck!
    ");
    }
    int main(){
    	while(scanf("%d%d%d%d",&m,&n,&k,&d)==4){
    		getchar();
    		memset(g,false,sizeof(g));
    		for(int i=0;i<k;i++){
    			scanf("%c",&cas[i].c);
    			scanf("%d%d%d%d",&cas[i].t,&cas[i].v,&cas[i].x,&cas[i].y);
    			getchar();    //吃掉换行 
    			g[cas[i].x][cas[i].y]=true;
    		}
    		solve();
    		bfs();
    	}
    	return 0;
    } 
    

    耗时 400ms

  • 相关阅读:
    MySQL8.0新增配置参数
    CF1153F Serval and Bonus Problem
    win10 uwp xaml 绑定接口
    win10 uwp xaml 绑定接口
    Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF 使用 UWP 控件
    Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF 使用 UWP 控件
    win10 uwp 渲染原理 DirectComposition 渲染
    dotnet 从入门到放弃的 500 篇文章合集
    C# ValueTuple 原理
    WPF 使用 Direct2D1 画图入门
  • 原文地址:https://www.cnblogs.com/RioTian/p/13099649.html
Copyright © 2011-2022 走看看