网上搜索的回溯法解决火力网问题基本上搜不出来,或者注释不明确,功能不完整。
火力网问题描述
假设我们有一个直街道广场的城市。一个城市的地图用n行n列的方形板,每一个代表一个街道或一块墙。
一个碉堡就是一个小城堡,有四个开口用以射击。四开口面朝北,东,南,西,分别。会有一个机枪射击通过每个开口。
在这里,我们假定子弹是如此强大,它可以运行在任何距离和毁灭的道路上一个碉堡。另一方面,墙是如此强烈地建成,可以阻止子弹。
其目标是把城市中的许多碉堡使没有两个可以摧毁对方。一个配置的碉堡是法律规定,没有两个碉堡是在地图上的同一行或列除非有至少一个墙壁将他们分离。
请问最多存在多少堡垒,并一一输出他们的情况。
你需要做的是规定方形城市的大小和墙壁的位置,
下图为一个可行的火力网示例
代码实现
#include <stdio.h>
int arr[100][100]={0};//0是空白 1是路 2是墙 3为碉堡 4为边界
int count ,n;
void makearr(int n){ //初始化数组 设置边界 和墙的位置
int i=0,j=0;
for(int x= 0;x<n;x++){
for (int y =0;y<n;y++)
{
arr[x][y]=1;
}
}
for(int a=0;a<n;a++){
arr[n][a]=4;
arr[a][n]=4;
}
printf("请输入墙的个数") ;
int sum;
scanf("%d",&sum) ;
for(int a=1;a<=sum;a++){
printf("请输入第%d块墙的具体行数",a);
scanf("%d",&i);
printf("请输入第%d块墙的具体列数",a);
scanf("%d",&j);
arr[i-1][j-1]=2;
}
}
void printarr(int n){ //打印城市情况
count++;
printf("\n%d:\n", count);
for(int i=0;i<n+1;i++){
printf("\n\n");
for (int j=0;j<n+1;j++){
if( arr[i][j]==1){
printf (" ") ;
}
else if (arr[i][j]==2)
printf("墙 ");
else if (arr[i][j]==3)
printf("堡 ");
else if (arr[i][j]==4)
printf("* ");
else if (arr[i][j]==0)
printf(" ");
}
}
}
int isTrue(int a, int b)
{
if(arr[a][b]!=1){
return 0;
}
int t;
for(t=a-1; t>=0; t--) // 向上判断
{
if(arr[t][b] ==2) break;
if(arr[t][b] ==3) return 0;
}
for(t=b-1; t>=0; t--){ // 向左判断
if(arr[a][t] == 2) break;
if(arr[a][t] == 3) return 0;
}
return 1;
}
void fun(int m){
if(m == n)
{
printarr(n); // 输出
return; // 递归出口
}
int i;
for(i=0; i<n; i++)
{
if(isTrue(m, i)) // 回溯算法
{
arr[m][i] = 3;
fun(m+1);
arr[m][i] = 1;
}
}
}
int main(){
printf("请输入边界N为多大") ;
scanf("%d",&n);
makearr(n);
fun(0);
return 0;
}
代码中fun为主要的回溯算法,定义一个m=0;m代表地图的行,从地图的第一行开始往下遍历,如果m能够达到最后一行而且完整运行,此时m数的大小由n-1变为n,fun结束,打印并结束此次递归。
部分运行结果