UVALive6661 Equal Sum Sets

来源:互联网 发布:fire in the hole知乎 编辑:程序博客网 时间:2024/05/18 05:01

         题目链接:https://icpcarchive.ecs.baylor.edu/external/66/6661.pdf

         题目大意:在给出的nks(n是不能超过的数)(k是要求的数字的个数)(s是数字的和)    

                            1<=n<=20   1<=k<=10    1<=s<=155

                            求出在满足条件下的解的个数

                                      比如n=9,k=3,s=23    有{6,8,9}                               一种

                                              n=9,k=3,s=22    有{5,8,9}      {6,7,9}        两种

 题目有三种方法来做: 

题解一:

DFS深搜

#include<cstring>#include<string>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>#define PI acos(-1.0)#define MAXN 100005#define eps 1e-7#define INF 0x7FFFFFFF#define ff sqrt(5.0)using namespace std;typedef long long ll;int n,k,s;int ans;void dfs(int x,int kk,int ss){    if (kk==k&&ss==s)    {        ans++;        return;    }    for (int i=x-1; i>=1; i--)    {        if (ss+i<=s)        {            dfs(i,kk+1,ss+i);   //第一次搜索完成之后 其值选择了一个,分别是(n)(n-1) (n-2)......(0)          }    }}int main(){    while(scanf("%d%d%d",&n,&k,&s),n|k|s)    {        ans=0;        dfs(n+1,0,0);          cout<<ans<<endl;    }    return 0;}
搜索的时候不用标记,用时100ms上下。


题解二:

二进制枚举

#include<cstring>#include<string>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>#define PI acos(-1.0)#define MAXN 100005#define eps 1e-7#define INF 0x7FFFFFFF#define ff sqrt(5.0)using namespace std;typedef long long ll;int main (){    int n,k,s;    while(scanf("%d%d%d",&n,&k,&s)&&(n||k||s))    {        int sum1=0,i,j;        for(i=2;i<(1<<(n+1));i++)        {            if(i%2==0) continue;            int sum=0,ans=0;            for(j=1;j<=n;j++)                if(i&(1<<j)) {sum+=j;ans++;}              if(sum==s&&ans==k) sum1++;        }        printf("%d\n",sum1);    }    return 0;}

题解三:

动态规划

#include<map>#include<set>#include<queue>#include<stack>#include<cmath>#include<cstdio>#include<vector>#include<string>#include<fstream>#include<cstring>#include<ctype.h>#include<iostream>#include<algorithm>#define INF (1<<30)#define PI acos(-1.0)#define mem(a, b) memset(a, b, sizeof(a))#define For(i, n) for (int i = 0; i < n; i++)typedef long long ll;using namespace std;int dp[22][160][11];int n, k, s;int main () {    dp[0][0][0] = 1;    for (int i = 1; i <= 20; i++) {        for (int j = 0; j <= 155; j++) {            for (int k = 0; k <= 10; k++) {                dp[i][j][k] = dp[i - 1][j][k];                if (k > 0 && j >= i) dp[i][j][k] += dp[i - 1][j - i][k - 1];            }        }    }    while(scanf("%d%d%d", &n, &k, &s), n || k || s) printf("%d\n", dp[n][s][k]);}

每一个dp[i][j][k]都是由以下方式选出的:

在i之前的数字中选出即: dp[i-1][j][k]

已经选过i了即:                dp[i-1][j-i][k-1]   在之前的i-1个数中选出k-1个数使得和是j-i   默认选过i了


0 0
原创粉丝点击