本篇看点PKU1011、PKU1013。
模拟题,没用公式,暴力0MS过了


int main()
{
int i,n,c,sum,pay;
while (scanf( " %d " , & n),n)
{
sum = 0 ;
pay = 1 ;
c = 0 ;
for (i = 1 ;i <= n;i ++ )
{
sum += pay;
c ++ ;
if (c == pay)
{
c = 0 ;
pay ++ ;
}
}
printf( " %d %d\n " ,n,sum);
}
return 0 ;
}
又是模拟题,题意:监狱门原本都锁着,经过n次题述操作后,看有多少监狱门是开着的。


#include < string .h >
int main()
{
int i,j,n,a[ 102 ],cas,sum;
scanf( " %d " , & cas);
while (cas -- )
{
scanf( " %d " , & n);
memset(a, 0 , sizeof (a));
for (i = 1 ;i <= n;i ++ )
{
for (j = 0 ;j <= n;j += i)
a[j] ++ ;
}
sum = 0 ;
for (i = 1 ;i <= n;i ++ )
if (a[i] % 2 )
sum ++ ;
printf( " %d\n " ,sum);
}
return 0 ;
}
思想:
①最少的盘子放了一个,这样每个盘子至少一个,n个盘子先放上n个,剩下的m-n个可以随便放
②最少的盘子没有放,这样剩下的n-1个盘子还是随便放m个


using namespace std;
int find( int m, int n)
{
if (m < 0 )
return 0 ;
if (m == 0 || n == 1 )
return 1 ;
return find(m - n,n) + find(m,n - 1 );
}
int main()
{
int t,m,n;
scanf( " %d " , & t);
while (t -- )
{
scanf( " %d%d " , & m, & n);
printf( " %d\n " ,find(m,n));
}
return 0 ;
}
网上搜的解题报告:
看到这道题立即想到了递归的经典案例:整数划分问题。
将正整数n表示成一系列正整数之和:n=n1+n2+…+nk, 其中n1≥n2≥…≥nk≥1,k≥1。
正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
例如正整数6有如下11种不同的划分:
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1。
将最大加数x不大于m的划分个数记作q(n,m) 有
1 n=1 || m=1
q(n,m) = { q(n,n) n<m
1+q(n,n-1) n=m
q(n,m-1)+q(n-m,m) n>m>1 重点在n>m>1的情况。
呵呵,当时我还花了好些功夫才理解到哦,真是精妙。有了这一点经验,放苹果的问题就容易了,我们也有递归式
将在m个盘中放n个苹果记作fun(m,n),且不能有空盘。(题目中的可以有空盘 不方便递归,我们循环累加)
对于fun(m,n)
1 n=1||m=n
resulut = 0 n<m
∑ fun(n-m,i) n>=m , i=1..n
当n>=m时,是不是方法和整数划分问题的n>m>1时很像呢?呵呵
PKU1011,PKU1013清华大学的《程序设计导引及在线实践》书上有详细讲解,这里就不多说了……
PKU1013枚举


#include < string .h >
char left[ 3 ][ 7 ],right[ 3 ][ 7 ],result[ 3 ][ 5 ];
bool isLight( char x)
{
int i;
for (i = 0 ;i < 3 ;i ++ ){
switch (result[i][ 0 ]){
case ' u ' : if (strchr(right[i],x) == NULL)
return false ; break ;
case ' e ' : if (strchr(left[i],x) != NULL || strchr(right[i],x) != NULL)
return false ; break ;
case ' d ' : if (strchr(left[i],x) == NULL)
return false ; break ;
}
}
return true ;
}
bool isHeavy( char x)
{
int i;
for (i = 0 ;i < 3 ;i ++ ){
switch (result[i][ 0 ]){
case ' u ' : if (strchr(left[i],x) == NULL)
return false ; break ;
case ' e ' : if (strchr(right[i],x) != NULL || strchr(left[i],x) != NULL)
return false ; break ;
case ' d ' : if (strchr(right[i],x) == NULL)
return false ; break ;
}
}
return true ;
}
int main()
{
int n;
char c;
scanf( " %d " , & n);
while (n -- ){
for ( int i = 0 ;i < 3 ;i ++ )
scanf( " %s%s%s " ,left[i],right[i],result[i]);
for (c = ' A ' ;c <= ' L ' ;c ++ ){
if (isLight(c)){
printf( " %c is the counterfeit coin and it is light.\n " ,c);
break ;
}
if (isHeavy(c)){
printf( " %c is the counterfeit coin and it is heavy.\n " ,c);
break ;
}
}
}
return 0 ;
}
PKU1011递归


#include < stdlib.h >
int cmp( const void * a, const void * b)
{
return * ( int * )b - * ( int * )a;
}
int n,sti[ 100 ],used[ 100 ];
int slove( int k, int left, int len)
{
int i;
if (k == 0 && left == 0 )
return 1 ;
if (left == 0 )
left = len;
for (i = 0 ;i < n;i ++ )
{
if (used[i] == 1 )
continue ;
if (sti[i] > left)
continue ;
used[i] = 1 ;
if (slove(k - 1 ,left - sti[i],len))
return 1 ;
used[i] = 0 ;
if (sti[i] == left || left == len) // 重点理解
break ;
}
return 0 ;
}
int main()
{
while (scanf( " %d " , & n),n)
{
int i,sum = 0 ,minlen,len;
for (i = 0 ;i < n;i ++ )
{
used[i] = 0 ;
scanf( " %d " , & sti[i]);
sum += sti[i];
}
qsort(sti,n, sizeof (sti[ 0 ]),cmp);
minlen = sti[ 0 ];
for (len = minlen;len <= sum;len ++ )
{
if (sum % len != 0 )
continue ;
if (slove(n, 0 ,len))
{
printf( " %d\n " ,len);
break ;
}
}
}
return 0 ;
}