POJ 刷水(2)
这一篇的看点PKU1088、PKU1012。
分析:先按H历法算出总天数,再模T历法一年的天数的到T历法的年,
但T历法没月的概念,只是两个独立循环的组合,所以分别模20和13就能得到结果。
数据4. uayet 259应输出13 ahau 364。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<string.h>
int main()
{
char HM[19][10]={"pop", "no", "zip", "zotz", "tzec", "xul", "yoxkin",
"mol", "chen", "yax", "zac", "ceh", "mac", "kankin", "muan", "pax",
"koyab", "cumhu", "uayet"};
char TD[20][10]={"imix", "ik", "akbal", "kan", "chicchan", "cimi", "manik",
"lamat", "muluk", "ok", "chuen", "eb", "ben", "ix", "mem", "cib",
"caban", "eznab", "canac", "ahau"};
int i,j,n,Hyear,Hday,Tyear,tds;//tds是totaldays总天数
char Hmonth[10];
scanf("%d",&n);
printf("%d\n",n);
for(i=1;i<=n;i++)
{
tds=0;
scanf("%d.%s %d",&Hday,Hmonth,&Hyear);
tds+=365*Hyear+Hday;//按Haab历计算总天数
for(j=0;j<19;j++) //循环累加求一年里的天数
if(strcmp(HM[j],Hmonth)==0)
{
tds+=j*20;
break;
}
Tyear=tds/260;
tds=tds%260;
printf("%d %s %d\n",tds%13+1,TD[tds%20],Tyear);//要加1
}
return 0;
}
分析:这是老师给的动态规划课件里面的一道例题,即数塔问题。和HDU2084题目一样,要是不懂题意可以去那里看中文。动态规划思想,从数塔下面往上面动态最优求和。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
int ma(int n,int m)
{
return n>m?n:m;
}
int main()
{
int n,a[102][102];
int i,j;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
scanf("%d",&a[i][j]);
for(i=n-2;i>=0;i--)
for(j=0;j<=i;j++)
a[i][j]=ma(a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1]);
printf("%d\n",a[0][0]);
}
return 0;
}
求一个二维数组的最长递减序列的长度(一个点滑向上下左右相邻四个点之一),对每个点都作为起点搜一次。
如果用常规的广度优先搜索方法,重复的子问题太多。对于其中的每个值都要广度搜索一次,找出其能够搜出的最大搜索次数,然后找出所有点的最大搜索次数的最大值。
用记忆化搜索,添加一个二维表,记忆每个搜索过的点的最大递归次数,当下一次搜索到该点时,就可以直接从二维表中直接取出来用就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<string.h>
int r,c,map[102][102],f[102][102];
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
bool ok(int x,int y)
{
return (x>=0 && x<r && y>=0 && y<c);
}
int find(int x,int y)
{
int i,fx,fy;
if(f[x][y]>0)
return f[x][y];
for(i=0;i<4;i++)
{
fx=x+dir[i][0];
fy=y+dir[i][1];
if(ok(fx,fy) && map[x][y]>map[fx][fy] && f[x][y]<find(fx,fy)+1)
f[x][y]=find(fx,fy)+1;
}
return f[x][y];
}
int main()
{
int i,j,mediate,max;
while(scanf("%d%d",&r,&c)!=EOF)
{
for(i=0;i<r;i++)
for(j=0;j<c;j++)
scanf("%d",&map[i][j]);
memset(f,0,sizeof(f));
max=0;
for(i=0;i<r;i++)
for(j=0;j<c;j++)
{
mediate=find(i,j);
if(max<mediate)
max=mediate;
}
printf("%d\n",max+1);
}
return 0;
}
太水了,不多说了。
约瑟夫问题,我先查到了位置坐标公式:f[i]=(f[i-1]+m-1)%(n-i+1);然后看了discuss上《总结三点》帖子
1.要kill的人的位置公式p=(p+m-1)%rest+1
2.kill的位置<k就break,此时剩下的人rest等于k就成功
3.m不要递增,m是k+1的整数倍或者k+1的整数倍加1,这样会提高不少
第三点不明白,就让m递增了,超时。
后又查找第三点的原因,在ericxieforever的专栏找到了答案。
另外这一题要把结果打表后再输出,不然还会超时。
分析:先引入Joseph递推公式,设有n个人(0,...,n-1),数m,则第i轮出局的人为f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0;
依次我们可以来做测试,只要前k轮中只要有一次f(i)<k则此m不符合题意。
接下来我们考察一下只剩下k+1个人时候情况,那么依题意则这一轮出局的人要么在上一轮出局人的左边,要么就在右边,则必有m%(k+1)==0或1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
int main()
{
int k,m,i;
int f,t,a[14];
for(k=1;k<14;k++){
t=0;
for(m=1; ;m+=((t++)%2?1:k)){
f=0;
for(i=1; ;i++){
f=(f+m-1)%(2*k-i+1);
if(f<k){
break;
}
}
if(i==k+1)
break;
}
a[k]=m;
}
while(scanf("%d",&k),k)
printf("%d\n",a[k]);
return 0;
}
对16以后的每个点从16个三维坐标中找距离最近的点形成映射。
挺简单,就贴代码了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<math.h>
const int SIZE = 100;
int pos[100];//记录对应的最小值所在位置
struct RGB
{
int red,green,blue;
}colors[SIZE];
double distance(RGB* color1,RGB* color2)
{
double r = color1->red-color2->red;
double g = color1->green-color2->green;
double b = color1->blue-color2->blue;
return sqrt(r*r+g*g+b*b);
}
int main(void)
{
double dist,min;
int count=0, r,g,b,i,j,k;
while (scanf("%d%d%d",&r,&g,&b),r+g+b!=-3)
{
colors[count].red = r;
colors[count].green = g;
colors[count].blue = b;
count++;
}
k=0;
for (i=16;i<count;++i)
{
min = 0xfffffff;
for (j=0;j<16;++j)
{
dist = distance(&colors[i],&colors[j]);
if (dist<min)
{
min = dist;
pos[k] = j;
}
}
k++;
}
for (i=16,k=0;i<count;++i,++k)
{
printf("(%d,%d,%d) maps to (%d,%d,%d)\n",colors[i].red,colors[i].green,colors[i].blue,colors[pos[k]].red,colors[pos[k]].green,colors[pos[k]].blue);
}
return 0;
}
二维数组找子矩形的最大和。(枚举+DP)
i从0到n-1循环,j从i到n-1循环,对i和j所指的行和其中间的行求和,得到一个一维数组,每次都求出这个一维数组的最大连续子序列,最大值即为结果。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
#include<string.h>
int map[100][100],n,temp[100],maxNum;
void findmaxNum()
{
int i,m = 0;
for(i=0;i<n;i++)
{
if(m>=0)
m += temp[i];
else
m = temp[i];
if(m>maxNum)
maxNum = m;
}
}
int main()
{
int i,j,k;
scanf("%d",&n);
maxNum = -222222222;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&map[i][j]);
for(i=0;i<n;i++)
{
memset(temp,0,sizeof(temp));
for(j=i;j<n;j++)
{
for(k=0;k<n;k++)
temp[k] += map[j][k];
findmaxNum();
}
}
printf("%d\n",maxNum);
return 0;
}
暴力0MS过的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h>
int len(int a)
{
int t=1;
while(a!=1)
{
if(a%2)
a=3*a+1;
else
a/=2;
t++;
}
return t;
}
int main()
{
int i,a,b,aa,bb,t,max;
while(scanf("%d%d",&a,&b)!=EOF)
{
aa=a; bb=b;
if(a>b)
{
t=a; a=b; b=t;
}
max=0;
for(i=a;i<=b;i++)
{
t=len(i);
if(max<t)
max=t;
}
printf("%d %d %d\n",aa,bb,max);
}
return 0;
}