洛谷P1025数的划分
洛谷P2386放苹果
整数的划分是一类DP的经典题,也可用递归解决。
数的划分:将整数ン分成KK份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
DFS版本:
#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:P1025 数的划分
//问题:将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
//解法:dfs
/*总结:
*/
int n,k,sum = 0;
void f(int num,int t,int j)//num表示总数,t表示划分的个数 j 表示当前划分最大值
{//按照递增的划分因此要记录 上一次划分的最大值 j
if(t==k)
{
if(num==n)
sum++;
return;
}
for(int i = j;i<=n;i++)
{
if(num+i*(k-t)>n) return;
if(num+i<=n)f(num+i,t+1,i);
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
f(0,0,1);
cout<<sum<<endl;
return 0;
}
DP版本:
#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:数的划分Dp
//问题:将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
//解法:dp 整数的划分
/*总结:
*/
int f[205][15];
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++)f[i][1] = 1;
for(int i = 1;i<=n;i++)
for(int j = 2;j<=m;j++)//从1开始会把初始化给盖掉
{
if(i>=j)f[i][j] = f[i-1][j-1]+f[i-j][j];
}
cout<<f[n][m]<<endl;
return 0;
}
放苹果DP + DFS:
#include<bits/stdc++.h>
#define maxn 100000+5
#define INF 0x3f3f3f3f
#define for1(i,l,r) for(int i=l;i<=r;++i)
#define for2(i,l,r) for(int i=l;i>=r;--i)
#define mst(a) memset(a,0,sizeof a)
#define ll long long
using namespace std;
//题号:放苹果
//问题:把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
//解法:递推 递归
/*总结:
f(m, n)表示将m个苹果放入n个盘子
f(10,3) = f(10, 2) + f(7, 3)
10个苹果放入3个盘子 = 10个苹果放入2个盘子(有空盘子,有一个盘子不放)
+ 7个苹果放入3个盘子(没有空盘子,每一个盘子里面先各放一个苹果,就只剩下7个苹果)
*/
int A[15][15];
int main()
{
ios::sync_with_stdio(false);
for1(i,0,10)//果
for1(j,1,10)//盘子
{
if(i==0||j==1)
{
A[i][j] = 1;
continue;
}
A[i][j] = A[i][j-1];
if(i>=j)A[i][j]+=A[i-j][j];
}
int n;
cin>>n;
for1(i,1,n)
{
int a,b;
cin>>a>>b;
cout<<A[a][b]<<endl;
}
return 0;
}
//dfs
int dfs(int m,int n){
if(m==0||n==1)
return 1;
if(n>m)
return dfs(m,m); //如果前面的小于后面的,则一定会有空盘子,则等于m个苹果放入m个盘子
else
return dfs(m,n-1)+dfs(m-n,n); //有空盘子的情况 + 没有空盘子的情况
}
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------
下面内容转自:HTTPS://blog.csdn.net/Athenaer/article/details/8265234
常见的有以下3种:
1。将n划分成不大于m的划分法:
2.将Ñ划分成ķ个数的划分法:
3.将ñ划分成若干奇数的划分法:
1.将Ñ划分成不大于米的划分法:
1)若是划分多个整数可以存在相同的:
dp [n] [m] = dp [n] [m-1] + dp [nm] [m] dp [n] [m]表示整数n的划分中,每个数不大于m的划分数。
则划分数可以分为两种情况:
a。划分中每个数都小于m,相当于每个数不大于m-1,故划分数为dp [n] [m-1]。
b。划分中有一个数为m。那就在n中减去m,剩下的就相当于把nm进行划分,故划分数为dp [nm] [m];
2)若是划分多个不同的整数。:
dp [n] [m] = dp [n] [m-1] + dp [nm] [m-1] dp [n] [m]表示整数n的划分中,每个数不大于m的划分数。
同样划分情况分为两种情况:
a。划分中每个数都小于m,相当于每个数不大于m-1,划分数为dp [n] [m-1]。
b。划分中有一个数为m。在n中减去m,剩下相当对nm进行划分,
并且每一个数不大于m-1,故划分数为dp [nm] [m-1]
2.将Ñ划分成ķ个数的划分法:
dp [n] [k] = dp [nk] [k] + dp [n-1] [k-1];
方法可以分为两类:
第一类:N份中不包含1的分法,为保证每份都> = 2,可以先拿出ķ个1分
到每一份,然后再把剩下的Ñ - K分成ķ份即可,分法有:DP [NK] [k]的
第二类:N份中至少有一份为1的分法,可以先那出一个1作为单独的1份,剩
下的n-1再分成k-1份即可,分法有:dp [n-1] [k-1]
3.将ñ划分成若干奇数的划分法:
G [i] [j]:将我划分为Ĵ个偶数
f [i] [j]:将我划分为j个奇数
g [i] [j] = f [i - j] [j];
f [i] [j] = f [i - 1] [j - 1] + g [i - j] [j];
方法可以分为两类:
第一类:ⅰ中拿出Ĵ个1分到每一份中,将剩余的IJ分成Ĵ个奇数
第二类:一份包含奇数1,剩余的I-1分成J-1个奇数;另一种,每份至少大于1,将Ĵ个1拿出来分到每一份中,其余IJ分成Ĵ份
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ----------------