01自然数的拆分问题
Description
任何一个大于 11 的自然数 nn,总可以拆分成若干个小于 nn 的自然数之和。现在给你一个自然数 nn,要求你求出 nn 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
Input
输入:待拆分的自然数 nn。
Output
输出:若干数的加法式子
#include<bits/stdc++.h>
using namespace std;
int n;
int a[20];
void dfs(int x,int s){
if(s==0){
for(int i=0;i<x-1;i++){
cout<<a[i]<<"+";
}cout<<a[x-1]<<endl;
return ;
}
for(int i=1;i<=s;i++){
if(i<a[x-1]){
continue;
}
a[x]=i;
dfs(x+1,s-i);
a[x]=0;
}
}
int main(){
cin>>n;
for(int i=1;i<=n/2;i++){
a[0]=i;
dfs(1,n-i);
}
return 0;
}
思路:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[10];//放答案(加数)
void dfs(int x,int s){
if(s==0){
for(int i=0;i<x-1;i++){
cout<<a[i]<<'+';
}cout<<a[x-1]<<endl;
return;
}//减到0停止
for(int i=1;i<=s;i++){
if(i<a[x-1]){
continue;
}//与上一个加数比较
a[x]=i;//放进去
dfs(x+1,s-i);//找下一个加数
a[x]=0;//还原
}
}
int main(){
cin>>n;
for(int i=1;i<=n/2;i++){
a[0]=i;//第一个加数,枚举(加数<=n/2)
dfs(1,n-i);//深搜
}
}
02填涂颜色
Description
由数字 00 组成的方阵中,有一任意形状的由数字 11 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 22。例如:6\times 66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:
如果从某个 00 出发,只向上下左右 44 个方向移动且仅经过其他 00 的情况下,无法到达方阵的边界,就认为这个 00 在闭合圈内。闭合圈不一定是环形的,可以是任意形状,但保证闭合圈内的 00 是连通的(两两之间可以相互到达)。
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 1 0 1
1 1 1 1 1 1
Copy
Plain text
0 0 0 0 0 0
0 0 0 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 1 2 1
1 1 1 1 1 1
Copy
Plain text
Input
每组测试数据第一行一个整数 n(1 \le n \le 30)n(1≤n≤30)。
接下来 nn 行,由 00 和 11 组成的 n \times nn×n 的方阵。
方阵内只有一个闭合圈,圈内至少有一个 00。
Output
已经填好数字 22 的完整方阵。
思路:
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=35;
int a[N][N];
int b[N][N];//将是1处的点当做走过,将里面的0围起来,b数组标记走过的点
void dfs(int x,int y){
if(x<0||x>n+1||y>n+1||y<0||b[x][y]==1){
return;
}//走过或者越界 截断 (向外补一圈)
if(a[x][y]==0){
b[x][y]=1;
}
dfs(x+1,y);
dfs(x-1,y);
dfs(x,y-1);
dfs(x,y+1);//四个方向
}
int main(){
cin>>n;
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]==1){
b[i][j]=1;
}
}
}
dfs(0,0);//从(0,0)开始深搜
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(b[i][j]==0){
cout<<2<<" ";//没走过的就是被围起来的
}
else{
cout<<a[i][j]<<" ";
}
}cout<<endl;
}
}
#include<bits/stdc++.h>
using namespace std;
int n;
int a[35][35];
int st[35][35];
void dfs(int x,int y){
if(x<0||x>n+1||y<0||y>n+1||st[x][y]==1){
return;
}
st[x][y]=1;
dfs(x+1,y);
dfs(x-1,y);
dfs(x,y+1);
dfs(x,y-1);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]==1){
st[i][j]=1;
}
}
}
dfs(0,0);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(st[i][j]==0){
cout<<2<<" ";
}
else{
cout<<a[i][j]<<" ";
}
}cout<<endl;
}
return 0;
03显示图像
Description
古老的显示屏是由 N \times MN×M 个像素(Pixel)点组成的。一个像素点的位置是根据所在行数和列数决定的。例如 P(2,1)P(2,1) 表示第 22 行第 11 列的像素点。那时候,屏幕只能显示黑与白两种颜色,人们用二进制 00 和 11 来表示。00 表示黑色,11 表示白色。当计算机发出一个指令:P(x,y)=1P(x,y)=1,则屏幕上的第 xx 行第 yy 列的阴极射线管就开始工作,使该像素点显示白色,若 P(x,y)=0P(x,y)=0,则对应位置的阴极射线管不工作,像素点保持黑色。在某一单位时刻,计算机以 N \times MN×M 二维 0101 矩阵的方式发出显示整个屏幕图像的命令。
例如,屏幕是由 3 \times 43×4 的像素点组成,在某单位时刻,计算机发出如下命令:
\begin{pmatrix} 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 1 \\ 0 & 1 & 1 & 0 \\ \end{pmatrix}000001011110
对应屏幕显示应为:
假设放大后,一个格子表示一个像素点。
由于未知的原因,显示黑色的像素点总是受显示白色的像素点的影响——可能是阴极射线管工作的作用。并且,距离越近,影响越大。这里的距离定义如下:
设有像素点 P_1(x_1,y_1)P1(x1,y1) 和像素点 P_2(x_2,y_2)P2(x2,y2),则它们之间的距离 D(P_1,P_2)=|x_1-x_2|+|y_1-y_2|D(P1,P2)=∣x1−x2∣+∣y1−y2∣。
在某一时刻,计算机发出显示命令后,科学家们期望知道,每个像素点和其最近的显示白色的像素点之间的最短距离是多少——科学家们保证屏幕上至少有一个显示白色的像素点。
上面的例子中,像素 P(1,1)P(1,1) 与最近的白色像素点之间的距离为 33,而像素 P(3,2)P(3,2) 本身显示白色,所以最短距离为 00。
Input
第一行有两个数字,NN 和 M\ (1 \le N,M \le 182)M (1≤N,M≤182),表示屏幕的规格。
以下 NN 行,每行 MM 个数字,00 或 11。为计算机发出的显示命令。
Output
输出文件有 NN 行,每行 MM 个数字,中间用 11 个空格分开。第 ii 行第 jj 列的数字表示距像素点 P(i,j)P(i,j) 最近的白色像素点的最短距离。
思路:
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=200;
char a[N][N];
int b[N][N];
bool v[N][N];
struct node{
int x,y,d;
};
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
queue<node>q;
void bfs(){
node next,now;
while(!q.empty()){
now=q.front();//头
int x=now.x,y=now.y,d=now.d;
q.pop();//拿出来
b[x][y]=d;//最短距离就是d
for(int i=0;i<4;i++){
int sx=x+dx[i];
int sy=y+dy[i];//往四面跑
if(sx>=1&&sx<=n&&sy>=1&&sy<=m&&a[sx][sy]=='0'&&v[sx][sy]==0){//没有越界
v[sx][sy]=1;//标记
next.x=sx;
next.y=sy;
next.d=d+1;//多了一步+1
q.push(next);//放进下一个
}
}
}
}
int main(){
node c;
cin>>n>>m;
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
if(a[i][j]=='1'){//注意是==‘1’
c.x=i;c.y=j;c.d=0;
q.push(c);//放进去
v[i][j]=1;//跑过
}//从1出发
b[i][j]=10000;
}
}
bfs();//开始广搜
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<b[i][j]<<" ";
}cout<<endl;
}//输出答案
}
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=200;
char a[N][N];
int b[N][N];
bool v[N][N];
struct node{
int x,y,d;
};
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
queue<node>q;
void bfs(){
node net,now;
while(!q.empty()){
now=q.front();
q.pop();
int x=now.x,y=now.y,d=now.d;
b[x][y]=d;
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&v[nx][ny]==0&&a[nx][ny]=='0'){
v[nx][ny]=1;
net.x=nx;
net.y=ny;
net.d=d+1;
q.push(net);
}
}
}
}
int main(){
node pp;
memset(v,0,sizeof v);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
if(a[i][j]=='1'){
pp.x=i;pp.y=j;
pp.d=0;
v[i][j]=1;
q.push(pp);
}
b[i][j]=100000;
}
}
bfs();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<b[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
04 健康的荷斯坦奶牛
Description
农民 John 以拥有世界上最健康的奶牛为傲。他知道每种饲料中所包含的牛所需的最低的维他命量是多少。请你帮助农夫喂养他的牛,以保持它们的健康,使喂给牛的饲料的种数最少。
给出牛所需的最低的维他命量,输出喂给牛需要哪些种类的饲料,且所需的饲料剂量最少。
维他命量以整数表示,每种饲料最多只能对牛使用一次,数据保证存在解。
Input
第一行一个整数 vv,表示需要的维他命的种类数。
第二行 vv 个整数,表示牛每天需要的每种维他命的最小量。
第三行一个整数 gg,表示可用来喂牛的饲料的种数。
下面 gg 行,第 nn 行表示编号为 nn 饲料包含的各种维他命的量的多少。
Output
输出文件只有一行,包括牛必需的最小的饲料种数 pp;后面有 pp 个数,表示所选择的饲料编号(按从小到大排列)。
如果有多个解,输出饲料序号最小的(即字典序最小)
思路:
#include<bits/stdc++.h>
using namespace std;
int v,g;
int need[30];
int a[20][30];
bool visit[20];
int ans[20];
int len;
int minn=15;
int sum[20];
int anss[20];
bool right(int x){
int f=0;
memset(sum,0,sizeof(sum));
for(int i=1;i<=v;i++){
for(int j=1;j<=len;j++){
sum[i]+=a[ans[j]][i];
}
}
for(int i=1;i<=v;i++){
if(sum[i]<need[i]){
f=1;break;
}
}
if(f==1){
return false;
}return true;
}
void dfs(int x){
if(x>g||x>minn){
return;
}//越界的和比之前的最小的大的 截枝
if(right(len)){//符合need
if(len<minn){
minn=len;
for(int i=1;i<=len;i++){
anss[i]=ans[i];
}
}return;
}
int start=ans[x];//从这种开始往下找 ,避免出现相同的答案
if(start==0){
start=1;
}
for(int i=start;i<=g;i++){
if(visit[i]==0){
visit[i]=1;
ans[x]=i;
len++;
dfs(x+1); //开始找下一种
ans[x]=0;//还原
len--;
visit[i]=0;
}
}
}
int main(){
cin>>v;
memset(visit,0,sizeof(visit));
for(int i=1;i<=v;i++){
cin>>need[i];
}
cin>>g;
for(int i=1;i<=g;i++){
for(int j=1;j<=v;j++){
cin>>a[i][j];
}
}
dfs(1);//开始找第一种饲料
cout<<minn<<" ";
for(int i=1;i<=minn;i++){
cout<<anss[i]<<" ";
}
}
#include<bits/stdc++.h>
using namespace std;
int v,g;
const int N=30;
int need[N];
int a[N][N];
bool st[N];
int sum[N];
int ans[N];
int minnn[N];
int minn=1000,len;
bool right(int l){
memset(sum,0,sizeof(sum));
for(int i=1;i<=l;i++){
for(int j=1;j<=v;j++){
sum[j]+=a[ans[i]][j];
}
}
for(int i=1;i<=v;i++){
if(sum[i]<need[i]){
return false;
}
}
return true;
}
void dfs(){
if(len>g||len>minn){
return;
}
if(right(len)){
if(minn>len){
minn=len;
for(int i=1;i<=len;i++){
minnn[i]=ans[i];
}
}return;
}
int start=ans[len];
if(start==0){
start=1;
}
for(int i=start;i<=g;i++){
if(!st[i]){
st[i]=1;
len++;
ans[len]=i;
dfs();
st[i]=0;
ans[len]=0;
len--;
}
}
}
int main(){
memset(st,0,sizeof(st));
cin>>v;
for(int i=1;i<=v;i++){
cin>>need[i];
}
cin>>g;
for(int i=1;i<=g;i++){
for(int j=1;j<=v;j++){
cin>>a[i][j];
}
}
dfs();
cout<<minn<<" ";
for(int i=1;i<=minn;i++){
cout<<minnn[i]<<" ";
}
}
05GRZ-Ridges and Valleys
给定一张地势图,求山峰和山谷的数量
思路:
#include<bits/stdc++.h>
using namespace std;
int n;
int ans1,ans2;
const int N=1005;
int a[N][N];
bool b[N][N];
int dx[8]={0,1,-1,0,1,1,-1,-1};
int dy[8]={1,0,0,-1,1,-1,1,-1};
int f1,f2;
void bfs(int x,int y){
queue<pair<int, int> >q;
q.push({x,y});//放进去
int h=a[x][y];//高度
while(!q.empty()){
int sx=q.front().first;
int sy=q.front().second;
q.pop();//拿出来
for(int i=0;i<8;i++){//从八面找
int nx=sx+dx[i];
int ny=sy+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n){//没有越界
if(a[nx][ny]==h&&b[nx][ny]==0){//高度一样,且没有标记过
b[nx][ny]=1;//标记
q.push({nx,ny});//放进去
}
if(a[nx][ny]<h){
f1=1;//注意不用标记
}
if(a[nx][ny]>h){
f2=1;
}
}
}
}
}
int main(){
cin>>n;
int f=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]!=a[1][1]){
f=1;
}
}
}
if(f==0){
cout<<1<<" "<<1<<endl;
return 0;
}//全都一样高
memset(b,0,sizeof(b));//全未标记过
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(b[i][j]==0){//没有标记过的点,未知是不是山峰或山谷
b[i][j]=1;//标记
bfs(i,j);//搜
if(f1==1&&f2==0){
ans1++;
}
if(f1==0&&f2==1){
ans2++;
}
f1=0;f2=0;
}
}
}
cout<<ans1<<" "<<ans2<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1005;
int a[N][N];
bool b[N][N];
int i,j;
int f1,f2;
int ans1,ans2;
int dx[8]={0,1,0,-1,1,1,-1,-1};
int dy[8]={1,0,-1,0,1,-1,1,-1};
void dfs(int x,int y){
b[x][y]=1;
queue<int>x1,y1;
x1.push(x);
y1.push(y);
while(!x1.empty()){
int xs=x1.front();
int ys=y1.front();
x1.pop();y1.pop();
for(int k=0;k<8;k++){
int nx=xs+dx[k];
int ny=ys+dy[k];
if(nx>=1&&nx<=n&ny>=1&&ny<=n){
if(a[nx][ny]==a[xs][ys]){
if(b[nx][ny]==0){
x1.push(nx);
y1.push(ny);
b[nx][ny]=1;
}
}
if(a[nx][ny]<a[xs][ys]){
f1=1;
}
if(a[nx][ny]>a[xs][ys]){
f2=1;
}
}
}
}
}
int main(){
cin>>n;
int f=0;
memset(b,0,sizeof(b));
for(int q=1;q<=n;q++){
for(int p=1;p<=n;p++){
cin>>a[q][p];
if(a[q][p]!=a[1][1]){
f=1;
}
}
}
if(f==0){
cout<<1<<" "<<1<<endl;
return 0;
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(b[i][j]==0){
dfs(i,j);
if(f1==1&&f2==0){
ans1++;
}
if(f1==0&&f2==1){
ans2++;
}
f1=0;
f2=0;
}
}
}
cout<<ans1<<" "<<ans2<<endl;
}
06八皇后 Checker Challenge
Description
一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:
行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6
列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。
Input
一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。
Output
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
思路:
#include<bits/stdc++.h>
using namespace std;
int n;
int m1[30],m2[30],m3[30];
int a[15];
void setvalue(int x,int y,int t){
m1[y]=t;
m2[x+y]=t;
m3[x-y+n]=t;
}
int mark;//mark表示总的数量
void bfs(int step){
if(step>n){mark++;
if(mark<=3){
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}cout<<endl;
}return;
}//如果>最后一行 输出 结束
for(int i=1;i<=n;i++){
if(m1[i]||m2[i+step]||m3[step-i+n]){
continue;
}//被标记过不可用
a[step]=i;//a数组存此行用哪一列的格子
setvalue(step,i,1);//用,然后标记
bfs(step+1);//下一行
a[step]=0;
setvalue(step,i,0);//还原
}
}
int main(){
cin>>n;
bfs(1);//从第一行开始
cout<<mark;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n,m1[30],m2[30],m3[30],ans[15];
int mark;
void setvalue(int x,int y,int t){
ans[x]=y;
m1[y]=t;
m2[x+y]=t;
m3[x-y+n]=t;
}
void dfs(int step){
if(step>n){mark++;
if(mark<=3){
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<endl;
}
return;
}
for(int j=1;j<=n;j++){
if(m1[j]||m2[step+j]||m3[step-j+n]){
continue;
}
setvalue(step,j,1);
dfs(step+1);
setvalue(step,j,0);
}
}
int main(){
cin>>n;
dfs(1);
cout<<mark;
return 0;
}