【codevs1039】01年noip TG--数的划分满分dp+愚蠢深搜+pas的奇怪做法
2015-08-08 17:12
330 查看
将整数n分成k份,且每份不能为空,任意两种划分方案不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种划分方案被认为是相同的。
1 1 5
1 5 1
5 1 1
问有多少种不同的分法。
输入:n,k (6<n<=200,2<=k<=6)
输出:一个整数,即不同的分法。
样例in:7
3
样例out:4
先说一下比较蠢(wo de)的做法,直接回溯,由于不知道怎么加优化然后就只得了80,最后一个数据取了极限值,1s内过不了╮(╯▽╰)╭
这段代码是通过前数比后数大来避免重复,但由于时间复杂度为指数级,所以会导致超时
#include<cstdio>
using namespace std;
void f(int,int);
int n,ans,k,a[1001]={1};
bool flag[1001]={true};
main()
{
scanf("%d%d",&n,&k);
f(n,1);
printf("%d",ans);
}
void f(int x,int y)
{
if (x==0&&y==k+1) {ans++;return;}
for (int i=a[y-1];i<=x;i++)
{
if (i<n)
{
x-=i;
a[y]=i;
f(x,y+1);
x+=i;
}
}
}
蒟蒻po主什么都不会,推导dp方程最后和标解一比发现错了(a[i][j]=a[i-1][j-1]+a[i-1][j]与a[i][j]=a[i-1][j-1]+a[i-j][j]),看来不细心认真,想敷衍了事是做不好什么东西的╮(╯▽╰)╭
#include<cstdio>
#include<iostream>
int a[2001][2001]={0};
using namespace std;
main()
{
int n,k;
//scanf("%ld%ld",&n,&k);
cin>>n>>k;
for (int i=1;i<=n;i++)
for (int j=1;j<=i;j++)
{
if (i==j) a[i][j]=1;
else if (j==1) a[i][j]=1;
else if (j>i) a[i][j]=0;//以上为几种特殊情况,其实有两条不加也并不影响什么
else a[i][j]=a[i-1][j-1]+a[i-j][j];//对于i,如果有1,我们要将它分成j份,那么我们可以取出一个1(有且仅有一个1作为单独的一份,然后i-1分成j-1份,即f1(i,j)=f(i-1,j-1);
//如果没有1,那么我们相当于把i-j分成j份,然后再给这j份分别加一个1,即f2(i,j)=f(i-j,j);
//最终得出f(i,j)=f1(i,j)+f2(i,j)=f(i-1,j-1)+f(i-j,j);
}
printf("%d",a
[k]);
}
还有一种很奇怪的用字符串的做法(pascal代码),好久以前写的不知道怎么的就过了,想了一下并总结也是类似于搜索的方法。
例如:n=7,k=3,下面三种划分方案被认为是相同的。
1 1 5
1 5 1
5 1 1
问有多少种不同的分法。
输入:n,k (6<n<=200,2<=k<=6)
输出:一个整数,即不同的分法。
样例in:7
3
样例out:4
先说一下比较蠢(wo de)的做法,直接回溯,由于不知道怎么加优化然后就只得了80,最后一个数据取了极限值,1s内过不了╮(╯▽╰)╭
这段代码是通过前数比后数大来避免重复,但由于时间复杂度为指数级,所以会导致超时
#include<cstdio>
using namespace std;
void f(int,int);
int n,ans,k,a[1001]={1};
bool flag[1001]={true};
main()
{
scanf("%d%d",&n,&k);
f(n,1);
printf("%d",ans);
}
void f(int x,int y)
{
if (x==0&&y==k+1) {ans++;return;}
for (int i=a[y-1];i<=x;i++)
{
if (i<n)
{
x-=i;
a[y]=i;
f(x,y+1);
x+=i;
}
}
}
蒟蒻po主什么都不会,推导dp方程最后和标解一比发现错了(a[i][j]=a[i-1][j-1]+a[i-1][j]与a[i][j]=a[i-1][j-1]+a[i-j][j]),看来不细心认真,想敷衍了事是做不好什么东西的╮(╯▽╰)╭
#include<cstdio>
#include<iostream>
int a[2001][2001]={0};
using namespace std;
main()
{
int n,k;
//scanf("%ld%ld",&n,&k);
cin>>n>>k;
for (int i=1;i<=n;i++)
for (int j=1;j<=i;j++)
{
if (i==j) a[i][j]=1;
else if (j==1) a[i][j]=1;
else if (j>i) a[i][j]=0;//以上为几种特殊情况,其实有两条不加也并不影响什么
else a[i][j]=a[i-1][j-1]+a[i-j][j];//对于i,如果有1,我们要将它分成j份,那么我们可以取出一个1(有且仅有一个1作为单独的一份,然后i-1分成j-1份,即f1(i,j)=f(i-1,j-1);
//如果没有1,那么我们相当于把i-j分成j份,然后再给这j份分别加一个1,即f2(i,j)=f(i-j,j);
//最终得出f(i,j)=f1(i,j)+f2(i,j)=f(i-1,j-1)+f(i-j,j);
}
printf("%d",a
[k]);
}
还有一种很奇怪的用字符串的做法(pascal代码),好久以前写的不知道怎么的就过了,想了一下并总结也是类似于搜索的方法。
var s:string; ans:longint; pan:boolean; procedure f(a:string); var i,t,e:longint; b:string; begin val(a,t,e); t:=t div 2; inc(ans); if t<>0 then begin for i:=1 to t do begin str(i,b); insert(b,a,1); f(b); end; end else exit; end; begin read(s); ans:=0; pan:=true; f(s); write(ans); end.
相关文章推荐
- C++编写简易的飞机大战
- KIDx's Pagination (周赛1)
- Python 3.4 学习总结(1)
- poj 1089 Intervals(区间合并问题)
- 树的遍历方式(不知道对不对)
- Linux常用命令大全
- hdu-2100-lovekey
- CodeForces 545A
- C++中引用(&)的用法和应用实例
- hongyang的博文深入理解Android中的自定义属性 学习笔记
- Vanya and Lanterns
- linux系统的颜色配置
- 快速幂
- Parcelable接口的使用
- HDU 1677 二分法进行判断
- 解决 Jenkins 没有权限监听 Gerrit 的 ‘Stream Events’的问题
- ZOJ 3430 Detect the Virus (AC自动机)
- 堆排序(初学者)
- jquery 实现可编辑div
- HDU A Mathematical Curiosity