学习时间:
早上8:40-8:50打卡签到。
9:30-12:30 看啊哈算法上面的深搜和宽搜。
14:30:18:00 刷题
19:00开始acwing每日一题
E - 棋盘问题
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
注意:深搜用每一行来循环,表示当前站在第x个格子前,就能够保证了行不会重复,然后我们用一个数组来标识列,用列来筛选,如果列用没重复就可以在这个格子里面放东西,这样就可以保证行和列都不重复,但是这个题和其他深搜的区别就是其他题每一行都能够放,但是这道题有个约束条件就是可能某一行或者某几行都不能放旗子,所以如果这时候没有能放的旗子,循环结束就返回到上一个调用了,而上一个调用假设在i++过后又能够放又来深搜这一层,而这一层一个都不能放,就又只能返回,所以这里就会导致不能对后面几行进行搜索就会跟理想的答案不符合,所以我们应该还需要在循环这一行的每列结束后还要对下一行进行深搜dfs(x+1);
#include <stdio.h>
#define N 30
char a[N][N];
int col[N]= {0};//列数的标识
int n,ans,m,k;
void dfs(int x)
{
int i;
if(m==k)//如果旗子已经和指定的k个相同方法数就加一
{
ans++;
return ;
}
if(x>=n)//如果行数超过了n就说明下一行不用测试了
return ;
for(i=0; i<n; i++)
{
if(!col[i]&&a[x][i]=='#')//x是代表行数,i代表列数,
//行数已经不会相同,所以我们要控制列数也不能相同,并且当前字符要是#
{
col[i]=1;//做个标记
m++;//旗子的个数
dfs(x+1);
//printf("i的值为:%d ans的值为%d x的值为:%d\n",i,ans,x);
col[i]=0;//调用过后要还原现场
m--;//还原现场所以加上的1要减去
}
} dfs(x+1);//printf("当x行没有旗子的时候可以进入下一行的搜索,以防直接返回上一行\n");
}
int main()
{
int i;
while(scanf("%d%d",&n,&k)&&n!=-1&&k!=-1)
{
ans=m=0;//多组数据每次要清0
for(i=0; i<n; i++)
scanf("%s",a[i]);
dfs(0);
printf("%d\n",ans);
}
}
H - Red and Black
There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.
Write a program to count the number of black tiles which he can reach by repeating the moves described above.
Input
The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.
There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.
‘.’ - a black tile
‘#’ - a red tile
‘@’ - a man on a black tile(appears exactly once in a data set)
Output
For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).
其实这个是啊哈算法上面求最小路径DFS的简化版,我们这里只要求可以走过的格子数,所以就可以不用还原现场,直接累加就行。
#include <stdio.h>
#define N 100
char a[N][N];
int sum=0,n,m;
int next[4][2]= {{0,1},{1,0},{0,-1},{-1,0}};//枚举的右、下、左上四个方向的搜索
void dfs(int x,int y)
{
int i,j,k;
for(k=0; k<4; k++)//对四个方向进行搜索
{
//printf("第%d次搜索\n",k);
i=x+next[k][0];
j=y+next[k][1];
if(i<0||i>=m||j<0||j>=n||a[i][j]=='#')//如果越界或者是红色的就直接进行下一次循环
continue;
if(a[i][j]=='.')//如果是黑色的就加一并且标号走过,
{
sum++;
//printf("当前位置是黑色sum++,sum的值为%d\n",sum);
a[i][j]='#';
dfs(i,j);
}
}
}
int main()
{
int i,j;
int x,y;
while(~scanf("%d%d",&n,&m)&&(n||m))
{
sum=1;
x=y=0;
getchar();
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
scanf("%c",&a[i][j]);
if(a[i][j]=='@')
{
x=i;
y=j;
a[x][y]='#';//这里因为要算初始位置所以可以先累加1并标号
}
}
getchar();
}
// printf("中心位置为%d %d:\n",x,y);
dfs(x,y);
printf("%d\n",sum);
}
}
> Catch That Cow
> Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
Input
Line 1: Two space-separated integers: N and K
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
Sample Input
5 17
Sample Output
4
Hint
The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
这个题一开始我还没看出来是个宽搜题,这道题跟啊哈算法中的用宽搜找小哈的那道题相似,不过这道题要简化了点,宽搜主要是用定义数组用入队的形式来存储,主要有三种走法,分别是N-1,N+1,N*2;因为这里的步数是根据它父亲的步数来更新的,所以要用个结构体来存储它的步数与当前的距离。
一开始WA了,改了一个多组输入才过的
#include <stdio.h>
#include <string.h>
#define N 100
struct node//结构体来存储当前值与步数
{
int x;
int step;
};
int main()
{
int book[100010]= {0};
struct node a[100010]= {0};
int i,j,m,n;
int y,k;
int flag=0;//定个标志表示暂时没有抓到牛
int head,tail;
while(~scanf("%d%d",&n,&m))
{
memset(book,0,sizeof(book));
memset(a,0,sizeof(a));
head=tail=flag=0;//入队的形式都赋值为0
if(n==m)
{
printf("0\n");
continue;
}
head=tail=0;//先对第一个数据入队
a[tail].x=n;
a[tail++].step=1;
book[n]=1;
while(head<tail)
{
for(k=0; k<3; k++)//三种不同的扩展方案
{
if(k==0)
y=a[head].x+1;
else if(k==1)
y=a[head].x-1;
else if(k==2)
y=a[head].x*2;
if(y<0||y>100001)//如果越界了就直接进入下一次扩展
continue;
if(book[y]==0&&y!=m)//如果当前数据没有入队并且没有抓到牛就入队
{
a[tail].x=y;
a[tail].step=a[head].step+1;
tail++;
book[y]=1;
}
if(y==m)//抓到了,就标识一下标志并结束内层循环
{
flag=1;
break;
}
}
if(flag==1)//抓到了就结束外层循环
break;
head++;//如果没有抓到就对下一个对象进行判断头要后移
}
printf("%d\n",a[head].step);//是头的步数
}
}
三.每日一题
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
第一行是一个整数T,代表一共有多少组数据。
接下来是T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C。
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目M。
因为只能向东或者向南走,所以到(i,j)只能从上面或者左边到达。
(i, j)从(i-1, j)即上方过来
(i, j)从(i, j-1)即左方过来
要从左上角到右下角,只要比较上面那个和左边那个哪个比较大,然后用大的加上右下角的那个就是最优解
#include <stdio.h>
#define N 1000
int a [N][N];
int f[N][N];//状态集合,f[i][j]指导(i,j)的最大花生数
int max(int d,int b)
{return d>b?d:b;
}
int main()
{int i,j,n,m,t;
scanf("%d",&t);
while(t--)
{scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];//上边和左边比较加上[i,j]
printf("%d\n",f[n][m]);
}
return 0;
}