P1162 填涂颜色
题目描述
由数字 00 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 11 构成,围圈时只走上下左右 44 个方向。现要求把闭合圈内的所有空间都填写成 22。例如:6\times 66×6 的方阵(n=6n=6),涂色前和涂色后的方阵如下:
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数 n(1 \le n \le 30)n(1≤n≤30)。
接下来 nn 行,由 00 和 11 组成的 n \times nn×n 的方阵。
方阵内只有一个闭合圈,圈内至少有一个 00。
//感谢黄小U饮品指出本题数据和数据格式不一样. 已修改(输入格式)
输出格式
已经填好数字 2 的完整方阵。
#include<stdio.h>
int n;
int a[35][35];//全局变量会自动初始化
int dx[4]={1,0,0,-1};
int dy[4]={0,1,-1,0};
void dfs(int x,int y)
{
if(a[x][y]==1)
return ;
if(a[x][y]==3)
return ;
a[x][y]=3;
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(0<=nx&&nx<n+2&&0<=ny&&ny<n+2&&a[nx][ny]==0)
dfs(nx,ny);
}
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);//从1开始,在原方阵外围一圈0
dfs(0,0);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(a[i][j]==0)
printf("2 ");
if(a[i][j]==3)
printf("0 ");
if(a[i][j]==1)
printf("1 ");
}
printf("\n");
}
}
在解决该题时碰到了瓶颈处,就是应该怎么找出被1围绕的0或者是在1之外的0。在1之外的0很难找,因为会在边缘处可能被1断开。想了很久,决定从题解中找点思路,发现可以在原方阵的外面围一圈0这样就可以避免找的时候发生中断。此外,还有一个注意的点就是,我根据上一题,进行了8个方位的搜索,
for(int dx=-1;dx<=1;dx++)
{
for(int dy=-1;dy<=1;dy++)
{
int nx=x+dx,ny=y+dy;
if(0<=nx&&nx<N&&0<=ny&&ny<M&&field[nx][ny]==0)
dfs(nx,ny);
}
但是这个题目只需要4个方位就可以了。
在函数dfs中还要判断出现a[x][y]=1和a[x][y]=3的情况或者在if语句中加上a[x][y]==0这个条件,避免搜索所有的数。
周老师的区间问题
周老师无聊时乱写了 n 个区间,但处女座的他随后又想将 n 个区间整理合并,但他发现区间太多了,于是他想请你帮帮他
输入
每次测试输入多组数据(小于100组),对于每组输入数据:
第一行为 n ,代表 n 个区间
接下来 n 行,每行两个数 s , t 代表区间 [s,t]
0 < n < 15000
0 <= s <= t < 10000000
输出
第一行输出一个数字 q ,代表合并后剩余的区间个数
随后 q 行 按从小到大的顺序输出区间
样例输入
3
2 4
1 3
7 7
样例输出
2
1 4
7 7
#include<stdio.h>
void qsort(long long int a[],long long int x,long long int y)
{
long long int i,j,t,temp;
if(x>y)
return ;
temp=a[x];
i=x;j=y;
while(i!=j)
{
while(a[j]>=temp&&i<j)
j--;
while(a[i]<=temp&&i<j)
i++;
if(i<j)
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
a[x]=a[i];
a[i]=temp;
qsort(a,x,i-1);
qsort(a,i+1,y);
return ;
}//快速排序
int main()
{
long long int n,left[15000],right[15000],i,j;
while(~scanf("%lld",&n))
{
for(i=0;i<n;i++)
scanf("%lld %lld",&left[i],&right[i]);
qsort(left,0,n-1);
qsort(right,0,n-1);
j=0;
for(i=1; i<n; i++)
{
if(left[i]<=right[j])
{
if(right[j]<=right[i])
right[j]=right[i];
continue;
}
else
{
j++;
left[j]=left[i];
right[j]=right[i];
}
}
printf("%lld\n",j+1);
for(i=0; i<=j; i++)
printf("%lld %lld\n",left[i],right[i]);
}
}
开始我想搞一个大的数组,把出现的区间赋值为0,但是这样组合区间的时候会比较麻烦。所以参照了别人的做法,直接对区间进行整合。我开始用冒泡排序,但是会时间超限,所以最好用快排。然后就是组合区间。如果先比较前一区间的left和后一区间的right判断有没有重合的部分,再判断是部分重合还是全部重合,全部重合就直接进行替换。
P1605 迷宫
题目描述
给定一个 N \times MN×M 方格的迷宫,迷宫里有 TT 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
输入格式
第一行为三个正整数 N,M,TN,M,T,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 SX,SY,FX,FYSX,SY,FX,FY,SX,SYSX,SY 代表起点坐标,FX,FYFX,FY 代表终点坐标。
接下来 TT 行,每行两个正整数,表示障碍点的坐标。
输出格式
输出从起点坐标到终点坐标的方案总数。
输入样例
2 2 1 1 1 2 2 1 2
输出样例
1
#include<stdio.h>
int N,M,T,SX,SY,FX,FY,k;
int t[15][2];//记录障碍物坐标
int book[10][10];
int dx[4]={1,0,0,-1};
int dy[4]={0,1,-1,0};
void dfs(int x,int y)
{
if(x==FX&&y==FY)
{
k++;
return ;
}//到达终点
else
{
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>0&&nx<=N&&ny>0&&ny<=M&&book[nx][ny]!=1)
{
book[nx][ny]=1;
dfs(nx,ny);
book[nx][ny]=0;
}
}
}
}
int main()
{
scanf("%d %d %d",&N,&M,&T);
scanf("%d %d %d %d",&SX,&SY,&FX,&FY);
for(int i=0;i<T;i++)
{
scanf("%d %d",&t[i][0],&t[i][1]);
int x=t[i][0],y=t[i][1];
book[x][y]=1;//把障碍物标记为1
}
book[SX][SY]=1;
dfs(SX,SY);
printf("%d",k);
}
还是选择搜索来依次找路线,如果找到终点就记录一次。在处理障碍物和走过的路,选择用二维数组book一起记录。在第一次编写出现了小错误,就是对于搜索的那一点我在dfs中给定book[x][y]=1,但是这样会把后续book[nx][ny]搞混。所以就在主函数中设置起点book[SX][SY]=1,方便之后判断下一位置。
题目描述
给定两个整数 n 和 m,要求 m个整数的和为n,m个整数的乘积最大。
满足条件的整数序列可能有多种,请你输出一个字典序最小的满足条件的序列。
输入
第一行输入两个整数 n和m (1 <= n <= 1e9), (1 <= m <= n <= 1e6)。
输出
输出m个用空格隔开的整数表示字典序最小的一种方案数。
#include<stdio.h>
int main()
{
long long int n,m,t,k,i;
scanf("%lld %lld",&n,&m);
t=n/m;k=m*(t+1)-n;
for(i=0;i<m;i++)
{
if(i<k)
printf("%lld ",t);
else
printf("%lld ",t+1);
}
}
开始看到题目,我想要不要用深度优先搜素试一试。但是很麻烦,既要计算乘积,还要判断字典序,所以我去听了关于这个题目的题解,发现就是简单的数学问题,乘积最小即m个数都向平均值靠拢的时候,再把剩余的在平均值后加1即可。
题目描述
阿丢呢离家进,最近胃口不好,吃不下去食堂的饭了,所以决定回家改善伙食。但是呢,阿丢自己做饭很慢很慢的,而很多时候呢下午要上课,没时间回去做饭吃。所以最后决定每3天(就是每隔两天)回去一次,注意每一年的第一天阿丢是要回家的。
比如2012年1月1日阿丢要回家,输出1。2012年1月4日(隔了2天)阿丢又可以回家了,输出2。依次类推。
输入
现在要你输入一个year,一个month,一个day。
输出
输出从你给的这一年的1月1号到你输入的时间点阿丢能回去了几次。输出格式照旧!测试数据多组
#include <stdio.h>
int main()
{
int year, month, day,n=1;
while(scanf("%d %d %d", &year, &month, &day)!=EOF)
{
int leap, sum,t;
switch (month)
{
case 1:sum = 0;break;
case 2:sum = 31;break;
case 3:sum = 59;break;
case 4:sum = 90;break;
case 5:sum = 120;break;
case 6:sum = 151;break;
case 7:sum = 181;break;
case 8:sum = 212;break;
case 9:sum = 243;break;
case 10:sum = 273;break;
case 11:sum = 304;break;
case 12:sum = 334;break;
default:printf("error\n");
}
sum = sum + day;
if (year%400 == 0 || year%4 == 0 && year%100 != 0)/*判断闰年*/
leap = 1;
else
leap = 0;
if(leap == 1 && month>2)
sum = sum+1;
if(sum<3)
t=1;
if(sum%3==0)
t=sum/3;
else if(sum%3!=0&&sum>3)
t=sum/3+1;
printf("Case #%d:\n%d\n",n,t);
n++;
}
return 0;
}
这个题目就是计算总天数,但是要注意总天数小于3的时候,还有恰好能整除的几种情况。
题目描述
众所周知,实验室的小叶子长的很黑,但是,他自己却总是喜欢颠倒黑白,总喜欢把黑的说成白的(比如 他自己,O(∩_∩)O哈哈~)。这不,有一天,他又开始了他的颠倒之路了。他拿出了两个数,试图颠倒这两个数。规则如下:如果这两个数的反转的和等于两个数和的反转,例如: 12和34。12的反转是21,34的反转是43,21+43=64,而12+34=46,46的反转为64。两个经过反转的数相等,那么他就颠倒失败了,否则他就成功了!!
输入
第一行一个正整数表示测试数据的个数n。
只有n行,每行两个正整数a和b(0<=a,b<=10000)。
输出
如果这两个数的反转的和等于两个数和的反转则输出a+b的值,否则输出小叶子颠倒成功。
#include<stdio.h>
#include<string.h>
#include<math.h>
int fan(char str[])
{
int l,i,sum=0;
l=strlen(str);
for(i=0;i<l;i++)
sum=sum+(str[i]-48)*pow(10,l-i-1);
return sum;
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int a,b,i;
scanf("%d %d",&a,&b);
char str1[10]={'\0'},str2[10]={'\0'},str3[10]={'\0'};
int x,y,t=a+b,k=t;
for(i=0;;i++)
{
str1[i]=a%10+48;
a=a/10;
if(a==0)
break;
}
for(i=0;;i++)
{
str2[i]=b%10+48;
b=b/10;
if(b==0)
break;
}
for(i=0;;i++)
{
str3[i]=t%10+48;
t=t/10;
if(t==0)
break;
}
y=fan(str1)+fan(str2);
x=fan(str3);
if(x==y)
printf("%d\n",k);
else
printf("小叶子颠倒成功\n");
}
}
这个题目我选择用字符数组做,这样方便反转。emm好像并没有很方便,但是答案正确。