数组上计数问题的动态规划-TopCoder-SRM584-DIV2-1000pt

题目描述:

http://community.topcoder.com/stat?c=problem_statement&pm=12644

给了两个数组,第一个的kind[i]对应城市i的类型。第二个为发现的类型,是一个set。

以及一个数字K,给出发现城市的数目。然后问题的那句英文不太好理解,意思其实是可能的发现的这些类型对应的城市都有哪些可能。

由于城市有标号,都是唯一的。所以可以将kind反过来统计,统计某种类型i ,对应的城市数目km[i]。

然后再将found数组扩展为fm,其中fm[i]表示类型i有没有被发现。

然后就是一个在类型上的计数问题了。

记 f (t , k) 为: 在已经确定了[t+1,n)类型的城市可能时。目前还有k个发现的城市没有确定下来,则余下的[0,t]共有多少种可能性?

对第t个类型,如果fm[t]=true ,说明发现了这种类型的城市,则枚举所有发现这种类型的城市的数目x,将问题规约到余下[0,t-1]类型和k-x个城市上。

也即:f (t,k) = sum (C(x,km[t])* f(t-1, k-x))。

而如果fm[t]=false,则发现了这种类型城市0个: f(t,k) = f(t-1,k)

再考虑一些边界条件即可。

一种基于memo的实现如下:

int m,n;
class Excavations2
        { 
        public: 
            vector <int> km;
            vector <bool> fm;
            int K;
            long long dp[51][51];
            long long comb[51][51];
            long long Solve(int t,int k){
                if (t==-1){            //left none types
                    if (k==0){return 1;}
                    return 0;
                }
                if (k==0){//non-discovered cities,but left some types unassigned
                    if (fm[t]){return 0;}
                }
                if (dp[t][k]!=-1){return dp[t][k];}
                long long res=0;
                if (!fm[t]){    //type t not discovered. k belongs to [0,t-1] types
                    res=Solve(t-1,k);
                }
                else{
                    int maxt=min(km[t],k);    //the limit make k>=0
                    for (int i=1;i<=maxt;i++){
                        //select i cities from km[t] cites
                        res+=(Comb(km[t],i)*Solve(t-1,k-i));
                    }
                }
                dp[t][k]=res;
                return res;
            }

            long long Comb(int a,int b){
                if (a==0){
                    if (b==0){return 1;}    //select 0 from 0
                    return 0;    //select b>0 from 0 elements: no way
                }
                if (b==0){    //a!=0
                    return 1;    //select 0 elements
                }
                if (comb[a][b]!=-1){return comb[a][b];}
                long long res=Comb(a-1,b-1)+Comb(a-1,b);
                comb[a][b]=res;
                return res;
            }
        long long count(vector <int> kind, vector <int> found, int K) 
            { 
                m=kind.size();
                int n=*max_element(kind.begin(),kind.end());
                km.resize(n,0);        //type i has km[i] cities
                for (int i=0;i<m;i++){
                    km[kind[i]-1]++;
                }
                fm.resize(n,false);    //fm[i]: type i has been found
                for (int i=0;i<found.size();i++){
                    fm[found[i]-1]=true;
                }
                this->K=K;
                memset(dp,-1,sizeof(dp));
                memset(comb,-1,sizeof(comb));
                return Solve(n-1,K);
            } 
};

 

posted @ 2014-09-22 21:16  zombies  阅读(166)  评论(0编辑  收藏  举报