Homework - DP1

UNIMODAL PALINDROMIC DECOMPOSITIONS // oj 1221

#include<iostream>
using namespace std;
int N;
long long cnt[250][250]; //属于i的结尾>=j的回文数 

int main(){
	for(int i=1;i<250;++i){
		cnt[i][i]=1;
		for(int j=i-1;j>0;--j){
			if(i>2*j) cnt[i][j]=cnt[i-2*j][j]+cnt[i][j+1]; //状态转移
			else if(i==2*j) cnt[i][j]=cnt[i][j+1]+1;
			else cnt[i][j]=cnt[i][j+1];
		} 
	}
	while(scanf("%d",&N)&&N){
		printf("%d %lld\n",N,cnt[N][1]);
	}
	return 0;
}

滑雪 // oj 1088

一遍过的代码,dfs & dp,表现不错,但还可以优化,日后再说

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int R,C,H[102][102];
int dp[102][102]={0}; //从(i,j)走出的最长路径 
int f(int i,int j){
	if(dp[i][j]) return dp[i][j];
	int t[4]={0};
	if(H[i-1][j]<H[i][j] && H[i-1][j]>-1) t[0]=f(i-1,j);
	if(H[i+1][j]<H[i][j] && H[i+1][j]>-1) t[1]=f(i+1,j);
	if(H[i][j-1]<H[i][j] && H[i][j-1]>-1) t[2]=f(i,j-1);
	if(H[i][j+1]<H[i][j] && H[i][j+1]>-1) t[3]=f(i,j+1);
	dp[i][j]=*max_element(t,t+4)+1;
	if(!dp[i][j]) dp[i][j]=1; //走到头了 
	return dp[i][j];
}

int main(){
	scanf("%d %d",&R,&C);
	memset(H,-1,sizeof(H));
	for(int i=1;i<=R;++i) for(int j=1;j<=C;++j) scanf("%d",H[i]+j);
	int maxL=0;
	for(int i=1;i<=R;++i) for(int j=1;j<=C;++j){
		int t=f(i,j);
		if(t>maxL) maxL=t;
	}
	cout<<maxL<<endl;
	return 0;
}

硬币 // oj 4120

高级的背包,虽然看上去简单,但可能是本次作业中最难的一道。

最终采用容斥原理法,还需日后细细琢磨。

#include<iostream>
#include<algorithm>
using namespace std;
//大背包类dp题目,请放弃dfs这种暴力的想法 
int n,x,c[10001];
int dp[10001]; //凑成i的方案数 
int ans[201]; //除去某个硬币后的方案数 
int get_ans(int x,int c){ //值为x,除去c后的方案数 
	if(x<0) return 0;
	return dp[x]-get_ans(x-c,c);
}

int main(){
	scanf("%d%d",&n,&x);
	for(int i=1;i<=n;++i) scanf("%d",c+i);
	dp[0]=1;
	for(int i=1;i<=n;++i) for(int j=x;j>=c[i];--j) dp[j]+=dp[j-c[i]];
	int t=0;
	for(int i=1;i<=n;++i) {
		if(get_ans(x,c[i])==0) ans[t++]=c[i];
	}
	cout<<t<<endl;
	for(int i=0;i<t;++i){
		cout<<ans[i];
		if(i==t-1) cout<<endl;
		else cout<<" ";
	}
	return 0;
}

最佳加法表达式 // oj 4152

看似复杂,但与“最长公共子序列”有相似的内核。

但是花的时间比较久,原因除了自身状态以外,主要有:

大整数和类有点生疏了,犯了一些结构性的错误;核心算法虽然好想,但各种参数的边界确实有点小麻烦。

#include<iostream>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
class CHugeInt {  
    public:  
        string s;  
        CHugeInt(){s='0';}  
        CHugeInt(const char *s_){ s=s_;}  
        CHugeInt(const string&s_):s(s_){}  
        string operator+(const CHugeInt&a){  
            int lena=s.size(), lenb=a.s.size(), maxm=lena>lenb?lena:lenb, tmp=0;  
            int arr_a[maxm], arr_b[maxm];  
            for (int i=0;i<maxm;++i){  
                if(lena-i-1>=0)arr_a[i]=s[lena-i-1]-'0';  
                else arr_a[i]=0;   
                if(lenb-i-1>=0)arr_b[i]=a.s[lenb-i-1]-'0';  
                else arr_b[i]=0;  
            }  
            for (int i=0;i<maxm;++i){  
                arr_a[i]+=(arr_b[i]+tmp);  
                if (arr_a[i]>9) {  
                    tmp=1;  
                    arr_a[i]-=10;  
                }  
                else tmp=0;  
            }  
            string result;  
            if(tmp) result+='1';  
            for (int i=tmp;i<maxm+tmp;++i)  
                result+=arr_a[maxm+tmp-i-1]+'0';  
            return result;  
        }  
        CHugeInt sub(int i,int j){ //[i,j)  
            if(i<j) return CHugeInt(s.substr(i,j-i));  
            else return CHugeInt(); //0  
        }  
        friend ostream& operator<<(ostream&o,const CHugeInt&a){  
            o<<a.s;  
            return o;  
        }  
};  
bool operator<(const CHugeInt&a,const CHugeInt&b){  
    if(b.s.size()!=a.s.size()) return a.s.size()<b.s.size();  
    return a.s<b.s; //长度一致的情况  
}  
int m; char s[52];  
CHugeInt dp[52][52]; //[0,i]插入j个加号的最小值 i<len  
  
int main(){  
    while(cin>>m>>s){  
        CHugeInt num(s);  
        int len=strlen(s);  
        for(int i=0;i<len;++i)  
        for(int j=0;j<=m;++j){  
            //if(i==0) dp[i][j]=num.sub(0,1);  
            if(j==0) dp[i][j]=num.sub(0,i+1);  
            else if(j<=i){  
            	CHugeInt nMin("999999999999999999999999999999999999999");
                for(int k=j;k<=i;++k){ //注意k的下界,坑死我了 
			CHugeInt t=num.sub(k,i+1)+dp[k-1][j-1];
			if(t<nMin) nMin=t; 
                }   
                dp[i][j]=nMin;
            }  
        }  
        cout<<dp[len-1][m]<<endl;   
    }  
    return 0;  
}  
后注:时间为 33ms,不是很突出,可能与Class的算法有关

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值