显示图像(bit)
【问题描述】
古老的显示屏是由N×M个象素(Pixel)点组成的。一个象素点的位置是根据所在行数和列数决定的。例如P(2,1)表示第2行第1列的象素点。那时候,屏幕只能显示黑与白两种颜色,人们用二进制0和1来表示。0表示黑色,1表示白色。当计算机发出一个指令:P(x,y)=1,则屏幕上的第x行第y列的阴极射线管就开始工作,使该象素点显示白色,若P(x,y)=0,则对应位置的阴极射线管不工作,象素点保持黑色。在某一单位时刻,计算机以N×M二维01矩阵的方式发出显示整个屏幕图像的命令。
例如,屏幕是由3×4象素点组成,在某单位时刻,计算机发出如下命令:
0001
0011
0110
距离定义:P1(x1,y1)和P2(x2,y2),距D(P1,P2):D(P1,P2)=|x1-x2|+|y1-y2|;
科学家们期望知道,每个象素点和其最近的显示白色的象素点之间的距离是多少——保证屏幕上至少有一个显示白色的象素点。
上面的例子中,象素P(1,1)与最近的白色象素点之间的距离为3,而象素P(3,2)本身显示白色,所以最短距离为0。
题目简述(bit):
一个图中所有点到1的最近距离;
输入格式:
第一行有两个数字,N和M (1<=N,M<=1000)。
以下N行,每行M个数字,0或1。
【输出格式】
输出文件有N行,每行M个数字,用1个空格分开。表示(i,j)离最近的白色象素点的距离。
【输入样例】
3 4
0001
0011
0110
【输出样例】
3 2 1 0
2 1 0 0
1 0 0 1
【数据范围】
对于30%的数据:N*M<=10000;
对于100%的数据:N*M<=1000^2。
分析:
搜索策略:bfs
当时是记录一遍,再扫一遍,找到1,就bfs;
值得借鉴的是:本题特点是多点同时搜索,可以用队列数组记录
出现1的坐标,这样可以同时开始,且不需多点间距离大小判断;
#include<cstdio>
#include<iostream>
#include<cstring>
#define INS 1001
using namespace std;
int n,m,p;
const int mx[]={0,0,-1,1},my[]={1,-1,0,0};
char ch[INS];
int ans[INS][INS];
int qx[1000000],qy[1000000];
void bfs();
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
cin>>ch;//字符串输入;
for(int j=0;j<m;j++)
if(ch[j]=='1') ans[i][j+1]=1,p++,qx[p]=i,qy[p]=j+1;//读到1入队,记录答案;
}
bfs();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%d ",ans[i][j]-1);
printf("\n");
}
return 0;
}
void bfs()
{
int h=0,t=p;
while(h<t){
h++;
for(int i=0;i<4;i++){
int xx=qx[h]+mx[i];
int yy=qy[h]+my[i];
if(xx>0&&yy>0&&xx<=n&&yy<=m&&ans[xx][yy]==0)
{
t++;
qx[t]=xx;
qy[t]=yy;
ans[xx][yy]=ans[qx[h]][qy[h]]+1;
}
}
}
}
生日蛋糕(cake)
【问题描述】
制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱。
当i<M时,半径递减,高度递减,Ri、Hi均为整数。
在蛋糕上抹奶油,尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q= Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
【输入格式】
输入最多10组数据,每组数据包含两个整数N和M。输入以一个0结尾。
【输出格式】
对于每组数据,输出一个整数S。
【输入样例】
100 2
1000 3
0
【输出样例】
68
316
【数据范围】
N<100001, M<11
分析:
1。搜索内容;
有层数,i,半径r,高度h,当前剩余体积v,当前表面积s;
2。3个减枝,比较难想,可行性,最优性减枝;
#include<iostream>
#include<cstdio>
#include<cmath>
#define f(i,a,b) for(register int i=a;i<=b;++i)
#define fd(i,a,b) for(register int i=a;i>=b;--i)
using namespace std;
const int N=20000+7;
int ans=987654321,n,m,Minv[N],Mins[N];
inline int read()//读入优化
{
int num=0;
char c;
while(isspace(c=getchar()));
while(num=num*10+c-48,isdigit(c=getchar()));
return num;
}
bool flag=1;
inline void dfs(int now,int S,int V,int lasth,int lastr)
{
if(now==0)//要是已经到了第一层就退出
{
if(V==n) ans=min(ans,S);//是否为合法答案
return;
}
//三重恶心的剪枝
if(S+2*(n-V)/lastr>ans) return;
//要是剩下体积除以最大(虽然取不到)半径=表面积,加上累计表面积>答案 退出
if(V+Minv[now]>n) return;//当前体积加上剩余层的最小体积还超过了约定体积,退出;
if(S+Mins[now]>ans) return;//最小面积+当前表面积>ans;
fd(i,lastr-1,now)//从大到小枚举该层半径
{
if(now==m) S=i*i;//第一层那么加上顶上表面积
int Maxh=min(lasth-1,(n-V-Minv[now-1])/(i*i));
fd(j,Maxh,now)//从大到小枚举该层高度
dfs(now-1,S+2*i*j,V+i*i*j,j,i);
}
}
int main()
{
n=read();m=read();
f(i,1,m)
Minv[i]=Minv[i-1]+i*i*i,//每一层的之后剩余最小体积;
Mins[i]=Mins[i-1]+2*i*i;//每一层的最小表面积
int MaxR=sqrt(n);
dfs(m,0,0,n,MaxR);
printf("%d",ans==987654321 ? 0 :ans);
return 0;
}
其中几个判断边界比较难,先预处理每一层的最小半径和剩余体积;
没一层的最小高度和半径都是当前层数,因为递增且为整数;
海盗船(corsair)
【问题描述】
有一个很有趣的游戏叫做海盗船。这是一个在9*8的棋盘上进行的游戏,棋盘上的每个格子可能是下面4种状态之一:
“.”:表示当前格子为空;
“S”:表示你的船所在的位置;
“E”:表示敌船所在的位置;
“#”:表示一座小岛。
每次你可以将你的船朝周围的8个方向之一移动,但不能停留。在你移动完之后,所有的敌船会朝周围8个位置中和你的船当前位置距离最近的那个格子移动。在这个过程中,如果某艘敌船碰到了小岛,那么这艘敌船将会沉没。如果两艘敌船同时走到同一个格子中,那么这两艘敌船将会同时沉没,并且其残骸将会在该位置形成障碍,也就是说如果还有敌船走到这个位置,那么该敌船也会沉没。每艘敌船上都装了烈性炸药,如果你不幸让某艘敌船撞到了你,你就可以和我们敬仰的祖先欢聚一堂了。
现在你的任务是通过移动你的船来消灭所有的敌船,当然,在移动过程中,请确保你的船不要撞倒小岛或者敌船的残骸。
【输入格式】
输入文件第一行包含一个整数T,表示测试数据组数,以下每组数据包含一个9*8的地图,地图上的符号以及意义如题目所述。相邻的两组数据间用一个空行隔开。
【输出格式】
输出文件对于每组数据输出一行信息。如果你能够消灭所有的海盗船,那么输出“I'm the king of the Seven Seas!”,否则输出“Oh no! I'm a dead man!”。
【输入样例】
2
........
........
........
...E....
...#S...
........
........
........
.......E
........
........
.....E..
..E#.#..
....S...
...#.#E.
...E....
........
........
【输出样例】
I'm the king of the Seven Seas!
Oh no! I'm a dead man!
【数据范围】