P2895 [USACO08FEB]流星雨 S
贝茜听说了一个骇人听闻的消息:一场流星雨即将袭击整个农场,由于流星体积过大,它们无法在撞击到地面前燃烧殆尽,届时将会对它撞到的一切东西造成毁灭性的打击。很自然地,贝茜开始担心自己的安全问题。
以 Farmer John 牧场中最聪明的奶牛的名誉起誓,她一定要在被流星砸到前,到达一个安全的地方(也就是说,一块不会被任何流星砸到的土地)。
如果将牧场放入一个直角坐标系中,贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。
根据预报,一共有 M M 颗流星 (1\leq M\leq50,000)(1≤ M≤50,000) 会坠落在农场上,其中第i颗流星会在时刻 T_i Ti (0\leq T_i\leq1,000)(0≤ Ti≤1,000) 砸在坐标为 (X_i, Y_i)( Xi, Yi) (0\leq X_i\leq 300(0≤ Xi≤300,0\leq Y_i\leq300)0≤ Yi≤300) 的格子里。流星的力量会将它所在的格子,以及周围 44 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。
贝茜在时刻 00 开始行动,它只能在第一象限中,平行于坐标轴行动,每 11 个时刻中,她能移动到相邻的(一般是 44 个)格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 t t 被流星撞击或烧焦,那么贝茜只能在 t t 之前的时刻在这个格子里出现。 贝西一开始在(0,0)(0,0)。
请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。如果不可能到达输出 -1−1。
Translated by @奆奆的蒟蒻 @跪下叫哥
输入输出样例
输入 #1复制
4 0 0 2 2 1 2 1 1 2 0 3 5
输出 #1复制
5
思路:bfs,如果题意理解有困难的话,把流星坠落的时间看成步数就好很多,比如 1 1 2,就是在贝茜走了两步时,流星就砸在1,1这个位置。所以在搜索时,在下一步走出前,注意是走出“前”,就判断下一步是否将坠落流星,有的话就先标记坠落地点及周围不能走,再遍历能走的地方就好了。
安全的标准是当前贝茜所处位置及周围在将来任意时刻都没有流星坠落。
这题还有个坑就是,只给出了炸弹的范围是300以内,其实贝茜的坐标是能超过300的,只要是第一象限都可以。
#include<stdio.h>
struct note {
int x;
int y;
int s;
};
struct note que[90005], boom[50005];
int a[405][405], book[405][405];
int main()
{
int m,flag=0;
scanf("%d", &m);
for (int i = 0; i < m; i++)
{
scanf("%d %d %d", &boom[i].x, &boom[i].y, &boom[i].s);
}
int tx, ty,tail=0,head=0;
int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
que[tail].x = 0;
que[tail].y = 0;
que[tail].s = 0;
tail++;
book[0][0] = 1;
while (head < tail)
{
for (int i = 0; i < m; i++)
{
if (boom[i].s == que[head].s +1)//假设现在在原点,如果在1时刻有流星坠落,那肯定不能去
{
book[boom[i].x][boom[i].y] = 1;//落点
for (int k = 0; k <= 3; k++)//周围
{
book[boom[i].x + next[k][0]][boom[i].y + next[k][1]] = 1;
}
}
}
for (int k = 0; k <= 3; k++)
{
tx = que[head].x+next[k][0];
ty = que[head].y+next[k][1];
if (tx < 0 || tx>300 || ty < 0 || ty>300)//299还是300?
{
continue;
}
if (book[tx][ty] == 0)
{
book[tx][ty] = 1;
que[tail].x = tx;
que[tail].y = ty;
que[tail].s = que[head].s + 1;
tail++;
//book[tx][ty] == 1;
}
flag = 0;//每次判断前都要初始化flag
//如果后面的流星都炸不到这个地方,那这就是安全的
for (int i = 0; i < m; i++)
{
for (int k = 0; k <= 3; k++)
{
if (tx + next[k][0] == boom[i].x && ty + next[k][1] == boom[i].y||tx== boom[i].x&&ty== boom[i].y)//还忽略了落点
{
flag = 1;//炸得到
break;
}
}if (flag == 1)
break;
}
if (flag == 0)
break;
}
if (flag == 0)
break;
head++;
}
if (flag == 0)printf("%d", que[tail - 1].s);
else printf("-1");
return 0;
}
P1219 [USACO1.5]八皇后 Checker Challenge
题目描述
一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 i i 个数字表示在第 i i 行的相应位置有一个棋子,如下:
行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6
列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。
输入格式
一行一个正整数 n n,表示棋盘是 n \times n n× n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入 #1复制
6
输出 #1复制
2 4 6 1 3 5 3 6 2 5 1 4 4 1 5 2 6 3 4
写题的时候还是多想想,说不定有更好的方法
第一遍写的时候想用四个数组把对应方向全部标记,正对角线好标记,副对角线硬是没找到规律(后来发现横坐标减去纵坐标的值恒为定值),就放弃了这个思路,于是我这个蒟蒻就写了2个函数,用来遍历对角线方向,和水平竖直方向是否被皇后占领。可想而知,超时了。
所以还是用四个标记吧。
#include<stdio.h>
int a[105], b[105], c[105], d[105],n,cnt=0;
void dfs(int y)//参数表示第几行
{
if (y-1 == n)
{
cnt++;
if (cnt <= 3)
{
for (int i = 1; i <= n; i++)
{
printf("%d ", a[i]);
}printf("\n");
}
return;
}
for (int i = 1; i <= n; i++)
{
if (b[i] == 0 && c[y + i] == 0 && d[y - i + 13] == 0)
{
a[y] = i;
b[i] = 1;
c[y + i] = 1;
d[y - i + 13] = 1;//副对角线中,横坐标与纵坐标相减会出现负数,但我们没有定义d[-3],所以可以加上13,例子中最大的数是12,加13可以保证不出现负数,唉,好像加11就可以了?
dfs(y + 1);
b[i] = 0;//回溯,取消标记
c[y + i] = 0;
d[y - i + 13] = 0;
}
}
return;
}
int main()
{
scanf("%d", &n);
dfs(1);
printf("%d", cnt);
return 0;
}