JRM
For many sets of consecutive integers from 1 through N (1 <= N <= 39), one can partition the set into two sets whose sums are identical.
For example, if N=3, one can partition the set {1, 2, 3} in one way so that the sums of both subsets are identical:
- {3} and {1,2}
This counts as a single partitioning (i.e., reversing the order counts as the same partitioning and thus does not increase the count of partitions).
If N=7, there are four ways to partition the set {1, 2, 3, ... 7} so that each partition has the same sum:
- {1,6,7} and {2,3,4,5}
- {2,5,7} and {1,3,4,6}
- {3,4,7} and {1,2,5,6}
- {1,2,4,7} and {3,5,6}
Given N, your program should print the number of ways a set containing the integers from 1 through N can be partitioned into two sets whose sums are identical. Print 0 if there are no such ways.
Your program must calculate the answer, not look it up from a table.
PROGRAM NAME: subset
INPUT FORMAT
The input file contains a single line with a single integer representing N, as above.SAMPLE INPUT (file subset.in)
7
OUTPUT FORMAT
The output file contains a single line with a single integer that tells how many same-sum partitions can be made from the set {1, 2, ..., N}. The output file should contain 0 if there are no ways to make a same-sum partition.
SAMPLE OUTPUT (file subset.out)
4
一开始的DFS,各种剪枝后还是果断超时
代码如下:
/*
ID: conicoc1
LANG: C
TASK: subset
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Number[40];
int N;
long long int count=0;
int Sum;
void DFS(int k,int SumOfSet)
{
int i,j;
int temp;
if((Sum/2-SumOfSet)<k-1)
k=Sum/2-SumOfSet+1;
for(i=k-1;i>=1;i--)
{
SumOfSet+=i;
/*********??????*/
temp=SumOfSet;
for(j=i-1;j>=1;j--)
{
temp+=j;
if(temp>=Sum/2)
break;
}
if(temp<Sum/2)
break;
/*****************/
if(SumOfSet<Sum/2)
DFS(i,SumOfSet);
if(SumOfSet==Sum/2)
{
count++;
}
SumOfSet-=i;
}
}
int main()
{
FILE *fin,*fout;
fin=fopen("subset.in","r");
fout=fopen("subset.out","w");
memset(Number,0,sizeof(Number));
fscanf(fin,"%d",&N);
int i;
for(i=1,Sum=0;i<=N;i++)
Sum+=i;
if(Sum%2==0)
DFS(N+1,0);
fprintf(fout,"%lld\n",count/2);
return 0;
}
改用DP:
/*
ID: conicoc1
LANG: C
TASK: subset
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int N;
long long int count=0;
int Sum;
long long int A[40][391]; //已决定了N个数,合为M时的情况
void subset()
{
int i,j;
for(i=0;i<=N;i++)
A[i][0]=1; //决定i个数,和为0的方案数都只有唯一1种(都不取)
for(i=1;i<=N;i++)
A[0][i]=0;
/*边界条件*/
for(i=1;i<=N;i++)
{
for(j=1;j<=Sum;j++)
{
if(j-i>=0)
A[i][j]=A[i-1][j-i]+A[i-1][j];
else
A[i][j]=A[i-1][j];
}
}
count=A[N][Sum];
}
int main()
{
FILE *fin,*fout;
fin=fopen("subset.in","r");
fout=fopen("subset.out","w");
memset(A,0,sizeof(A));
fscanf(fin,"%d",&N);
int i;
for(i=1,Sum=0;i<=N;i++)
Sum+=i;
if(Sum%2==0)
{
Sum/=2;
subset();
}
fprintf(fout,"%lld\n",count/2);
return 0;
}
做完这题我觉得得先去NOCOW上面好好理解一下背包问题
动态规划的题目据说千变万化啊= =