• URAL 1244


    题目大意:给出一个正整数M,给出N个正整数ai,让你在这些数中挑出一些数组成M的一个划分,如果符合条件的划分数超过两个,输出:-1,如果没有输出:0,如果有且仅有一个:则按顺序输出剩下的数的序号。

    例如:

    inputoutput
    270
    4
    100
    110
    170
    200
    
    2 4
    
    270
    4
    100
    110
    160
    170
    
    -1
    
    270
    4
    100
    120
    160
    180
    
    0

        

        测例1中,有且仅有100+170=270,所以输出110与200的序号2 4。测例2中,100+170=160+110=270,所以输出-1。测例3中,没有任何两个数的和为270,所以输出0。

    Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    数据规模:0<ai<=1000,2<=N<=100。

    理论基础:无。

    题目分析:我们用dp[i][j]表示仅用前i个数可以挑出的j的划分的个数。pre[i][j]表示第i个数被选择或者未被选择,用于最后输出结果。

    我们可以得出如果需要输出时,那么方案数就是唯一的,所以途径的所有的状态的数都只能是被选或者未被选择,所以我们不用担心,a[i]被选与未被选都有解的情况。因为这时我们不需要输出。

    下来是状态转移方程:dp[i][j]=dp[i-1][j]+(j>=a[i])*(dp[i-1][j-a[i]]);在每一层dp时,只要发现dp[i][M]大于等于2即可输出-1退出程序。

    如果dp[N][M]为0,则输出0。否则,回溯找回答案并输出。

    代码如下:

     

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<ctime>
    #include<vector>
    using namespace std;
    typedef double db;
    #define DBG 0
    #define maa (1<<31)
    #define mii ((1<<31)-1)
    #define ast(b) if(DBG && !(b)) { printf("%d!!|
    ", __LINE__); while(1) getchar(); }  //调试
    #define dout DBG && cout << __LINE__ << ">>| "
    #define pr(x) #x"=" << (x) << " | "
    #define mk(x) DBG && cout << __LINE__ << "**| "#x << endl
    #define pra(arr, a, b)  if(DBG) {
        dout<<#arr"[] |" <<endl; 
        for(int i=a,i_b=b;i<=i_b;i++) cout<<"["<<i<<"]="<<arr[i]<<" |"<<((i-(a)+1)%8?" ":"
    "); 
        if((b-a+1)%8) puts("");
    }
    template<class T> inline bool updateMin(T& a, T b) { return a>b? a=b, true: false; }
    template<class T> inline bool updateMax(T& a, T b) { return a<b? a=b, true: false; }
    typedef long long LL;
    typedef long unsigned int LU;
    typedef long long unsigned int LLU;
    #define N 100
    #define M 100000
    int dp[N+1][M+1];
    int a[N+1],sum,n,cnt,ans[N+1];
    bool pre[N+1][M+1];
    int main()
    {
        scanf("%d%d",&sum,&n);
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        dp[1][0]=1,dp[1][a[1]]=1,pre[1][a[1]]=true;
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=sum;j++)
            {
                dp[i][j]=dp[i-1][j]+(j>=a[i])*dp[i-1][j-a[i]];
                if(dp[i-1][j-a[i]])pre[i][j]=true;
            }
            if(dp[i][sum]>=2)
            {
                printf("-1
    ");
                return 0;
            }
        }
        if(dp[n][sum]==0)
        {
            printf("0
    ");
            return 0;
        }
        if(dp[n][sum]==1)
        {
            for(int i=n;i>=1;i--)
            {
                if(!pre[i][sum])ans[++cnt]=i;
                sum=sum-a[i]*pre[i][sum];
            }
            pra(ans,1,cnt)
            for(int i=cnt;i>=1;i--)
            {
                printf("%d%c",ans[i],i==1?'
    ':' ');
            }
        }
    	return 0;
    }

       其中的初始化细节处理很容易理解,所以不用再细说了。

    by:Jsun_moon http://blog.csdn.net/jsun_moon


  • 相关阅读:
    2013暑假集训B组训练赛第二场
    2013暑假集训B组训练赛第二场
    2013暑假集训B组训练赛第二场
    2013暑假集训B组训练赛第二场
    SPOJ ANARC05H 计数DP
    HDU 2586 LCA-Tarjan
    POJ 1330 LCA最近公共祖先 离线tarjan算法
    Codeforces 176B 经典DP
    UVA 10564 计数DP
    HDU 4901 多校4 经典计数DP
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3279734.html
Copyright © 2020-2023  润新知