算法课作业 5

编程入门 行业动态 更新时间:2024-10-28 02:27:48

算法课<a href=https://www.elefans.com/category/jswz/34/1771149.html style=作业 5"/>

算法课作业 5

题意重述

给定n(20)和m(20),表示一个n*m的网格,可在格点上放置机器人,机器人会使所在格点和上下左右格点都进入监视状态,问最少放置多少个机器人会使得所有格点都进入监视状态?

解法分析

使用回溯法,从上到下从左到右依次使得每个访问过的格子都进入监视状态.
让未进入监视状态的当前格点进入监视状态只有三种情况,在当前节点放置机器人,在右侧节点放置机器人,在下方节点放置机器人,依次递归判断.
记录初始的最优值为一个最大值,每次放完后与当前最优值比较并更新答案.

实现细节

1.剪枝策略:

  1. 可以证明,放置的机器人个数不会超过nm/3+1个(按每个机器人仅辐射左右或上下考虑,堆叠这样的小长条,最后只会剩下11,12,22三种剩余,都满足).以n*m/3+2为初始最优值,当放置的个数超过当前最优值时,剪去.
  2. 可以证明,当前访问的格点(i,j)已被监视时,放置在(i,j)的情况一定不会比放置在(i+1,j+1)的情况好.当(i+1,j+1)不在网格中时,(i+1,j)和(i,j+1)同理.所以,如果(i,j)已被监视,则不需要在此处放置机器人,直接跳过即可.
    (update,证明:因为是从上到下从左到右使得格子进入监视状态,当前正在检查访问(i,j)。说明在这之前的(i-1,j)和(i,j-1)已被监视。此时如果放在(i,j)处,只会使得(i+1,j)和(i,j+1)进入访问状态。而如果放在(i+1,j+1)处,显然在完成上述目标的情况下可以使更多格子进入访问状态)
  3. 当(i,j)未被监视时,若(i,j+1)已被监视,则在(i,j)放置一定不会比在(i+1,j)放置的情况好.所以当且仅当(i,j)在网格右下角或者(I,j+1)未被监视时才考虑放置在(i,j)的情况.
  4. 当(i,j)未被监视时,若(i,j+1)和(i,j+2)均被监视,则在(i+1,j)放置一定不会比在(i+1,j)放置的情况好,所以当且仅当(i,j+1)或(i,j+2)未被监视时才考虑放置在(i,j+1)的情况.
  5. 当i=n时,不考虑放置在(i+1,j)的情况.
  6. 记录已经监视的格点数,(当前最优值减去当前已放置个数)*5如果小于未监视的格点数,则一定达不到比当前最优值更好的情况,剪去.
  7. 类似于(6),考虑更紧的情况,并非每个机器人都能独立监视5个格点,至少会有m/4+5的冗余,这个剪枝仅适用于i<n-1的情况,因为最后两行由于最优值和已放置个数非常接近,总是达不到这个值.这个剪枝策略参考自习题答案.

2. 记录已被监视的节点个数.

是否被监视使用一个int而不是bool数组spy,初始化时将网格周围一圈都设为1.每添加一个机器人,将它本身及上下左右的spy都+1,取消一个机器人时则-1.当添加后为1时,表示这个节点新被监视,当取消后为0时,表示这个节点新被取消监视.

代码

/* LittleFall : Hello! */
#include <bits/stdc++.h>
const int M = 32, go[5][2]={{0,0},{0,1},{0,-1},{1,0},{-1,0}};int n,m;
int anx[M][M], ans;
int put[M][M], spy[M][M], tmp, spys = 0;
int lim1, lim2;void search(int i,int j);
void puta(int x,int y,int i,int j)
{put[x][y] = 1;tmp++;for(int i=0; i<5; ++i)if(++spy[x + go[i][0]][y + go[i][1]]==1) spys++;search(i,j+1);put[x][y] = 0;tmp--;for(int i = 0; i < 5; ++i)if(--spy[x + go[i][0]][y + go[i][1]]==0) spys--;
}
void search(int i,int j)
{if(tmp>=ans) return;while(i<=n && spy[i][j]) //已放置的不再被搜索{++j;if(j>m)	++i, j=1;}if(i>n)					//更新答案{ans = tmp;memcpy(anx, put, sizeof(put));return;}int reach = spys + (ans-tmp)*5;if(reach <= lim1) return;if(i<n-1 && reach <= lim2) return;if((i==n&&j==m) || spy[i][j+1]==0) puta(i,j,i,j);if(i<n) puta(i+1,j,i,j);if(j<m && (spy[i][j+1]==0 || spy[i][j+2]==0)) puta(i,j+1,i,j);
}
int main(void)
{freopen("5-17.txt","r",stdin);scanf("%d%d",&n,&m);ans = n * m / 3 + 2;lim1 = n * m, lim2 = n * m + m / 4 + 5;for(int i=0;i<=n+1;++i)spy[i][0] = spy[i][m+1] = 1;for(int i=0;i<=m+1;++i)spy[0][i] = spy[n+1][i] = 1;search(1,1);printf("%d\n",ans );for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)printf("%d%c",anx[i][j],j==m?'\n':' ' );return 0;
}

更多推荐

算法课作业 5

本文发布于:2024-02-17 19:50:58,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1695263.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:作业   算法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!