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的算法有关