POJ 3181 Dollar Dayz

       其实这道题就是简单的完全背包问题。从低到高推断出每种硬币的所有面额的解即可。当然,离线的话会慢一点。可以将问题需要求出的子问题全部求出来。下一个问题出现的时候,如果之前已经求解过则不必求解,否则在之前的基础上继续求解。原本觉得没什么好写的,关键是同样的方法用STL中的vector代替数组会超时!搞得以后都不敢用STL了.....

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define MAXN 1000+5
#define MAXK 100+5
#define MAXL 200
using namespace std;

char ans[MAXK][MAXN][MAXL];
int vis[MAXK][MAXN];
int L[MAXK][MAXN];//答案的长度记录
void add(int,int);
void doit(int,int,int,int);

int main()
{
    memset(vis,0,sizeof(vis));
    for(int i=0;i<MAXN;i++) {ans[1][i][1]='1';vis[1][i]=1;L[1][i]=1;}//K=1
    for(int i=1;i<MAXK;i++) {ans[i][0][1]='1';vis[i][0]=1;L[i][0]=1;}//N=0


    int N,K;
    int LK=1,LN=0;//LK,LN记录上次求解到的位置
    while(cin>>N>>K){
        if(!vis[K][N]) {doit(LK,LN,K,N);LK=K,LN=N;}
        for(int i=L[K][N];i>0;i--)
            cout<<ans[K][N][i];
        cout<<endl;
    }
}

void doit(int LK,int LN,int K,int N)
{
    for(int i=LK+1;i<=K;i++){
        for(int j=1;j<i;j++) {
            if(vis[i][j]) continue;
            for(int k=1;k<=L[i-1][j];k++) ans[i][j][k]=ans[i-1][j][k];
            L[i][j]=L[i-1][j];
            vis[i][j]=1;
        }
        for(int j=i;j<=N;j++) {
            if(vis[i][j]) continue;
            add(i,j);
            vis[i][j]=1;
        }
    }
}


void add(int k,int n)//高精度加法运算
{
    int len;

    for(int i=1;i<=L[k-1][n];i++) ans[k][n][i]=ans[k-1][n][i];//先复制一个序列
    L[k][n]=L[k-1][n];

    len=max(L[k][n],L[k][n-k]);

    int sum,overflow=0;
    for(int i=1;i<=len;i++){
        if(L[k][n-k]<i){//根据两序列长度不同分类讨论
            sum=ans[k][n][i]-'0'+overflow;
        }
        else {
            if(L[k][n]<i) {ans[k][n][i]='0';L[k][n]++;}
            sum=ans[k][n][i]-'0'+ans[k][n-k][i]-'0'+overflow;
        }
        ans[k][n][i]=sum%10+'0';
        overflow=sum/10;
    }
    if(overflow){//最后还有进位
        len=++L[k][n];
        ans[k][n][len]=overflow+'0';
    }

    return ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值