POJ刷水(3)
本篇看点PKU1011、PKU1013。
模拟题,没用公式,暴力0MS过了
#include<stdio.h>
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<stdio.h>
#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个
#include<iostream>
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<stdio.h>
#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<stdio.h>
#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;
}