CJOJ 1071 【Uva】硬币问题(动态规划)

Description

有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多。给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值。

Input

第一行两个整数,n,S(1≤n≤100, 0≤S≤100000)。

第二行n个整数vi-1...n(1≤vi≤S)。

Output

第一行两个整数,分别表示硬币数目的最小值 a 和最大值 b 。无解则输出 -1 。

第二行 a 个整数分别表示使用的是第几种硬币。

第三行 b 个整数分别表示使用的是第几种硬币。

Sample Input

6 12

1 2 3 4 5 6

Sample Output

2 12

6 6

1 1 1 1 1 1 1 1 1 1 1 1

Http

CJOJ:http://oj.changjun.com.cn/problem/detail/pid/1071

Source

动态规划

解决思路

看到这道题首先想到的是spfa算法。令每一个面值为一个点,若面值j=i+v[k]则连一条边(只是这么想,实际不用连边),那么分别用spfa跑出0->S的最短路径和最长路径。

这么想虽然没错,但会超时(70分)。下面会给出spfa代码,这里就不过多叙述。

那么正解是什么呢?动态规划

我们以求最小值为例,定义Dmin[i]表示能凑出面值i的最少硬币数,用path_min[i]记录这个数量是从哪个面值转移过来的。那么我们就有Dmin[i]=min(Dmin[i-V[j]]+1)

最后求路径的时候先令一个变量k=S,每次将k-path_min[k]压入一个vector中,再将k=path_min[k],直到k==0。然后将vector排序,再输出。

而最大值的操作是类似的。

另外要注意的是,题中输出的应该是面值的编号,所以用一个Map[i]存下面值i对应的编号,所以压入vector的就是Map[k-path_min[k]]

代码

spfa(TLE代码)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std; const int maxN=200;
const int maxS=100050;
const int inf=2147483647; int n,S;
int V[maxN];
int Dmax[maxS];
int Dmin[maxS];
int path_max[maxS];//记路径
int path_min[maxS];
bool vis[maxS];
int Map[maxS];//因为最后要输出的是编号,所以为每一个面值都存一个编号
queue<int> Q;
vector<int> arr; void spfa_min();
void spfa_max();
void dfs_min(int sum);//dfs求答案,但会爆栈
void dfs_max(int sum); int main()
{
memset(Dmax,-1,sizeof(Dmax));
memset(Dmin,-1,sizeof(Dmin));
memset(Map,-1,sizeof(Map));
cin>>n>>S;
for (int i=1;i<=n;i++)
{
cin>>V[i];
if (Map[V[i]]==-1)
Map[V[i]]=i;//记录面值i所对应的的编号i
}
spfa_min();
spfa_max();
cout<<Dmin[S]<<' '<<Dmax[S]<<endl;
//dfs_min(S);cout<<endl;
//dfs_max(S); int k=S;//手动写栈,排序
while (k>0)
{
arr.push_back(Map[k-path_min[k]]);
k=path_min[k];
}
sort(arr.begin(),arr.end());
for (int i=0;i<arr.size();i++)
cout<<arr[i]<<' ';
cout<<endl; k=S;//手动写栈,排序
arr.clear();
while (k>0)
{
//cout<<":AA"<<endl;
arr.push_back(Map[k-path_max[k]]);
k=path_max[k];
}
sort(arr.begin(),arr.end()); for (int i=0;i<arr.size();i++)
cout<<arr[i]<<' ';
cout<<endl;
return 0;
} void spfa_min()
{
memset(vis,0,sizeof(vis));
Q.push(0);
vis[0]=1;
Dmin[0]=0;
do
{
int u=Q.front();
Q.pop();
vis[u]=0; for (int i=1;i<=n;i++)
if (u+V[i]<=S)
if ((Dmin[u]+1<Dmin[u+V[i]])||(Dmin[u+V[i]]==-1))
{
Dmin[u+V[i]]=Dmin[u]+1;
path_min[u+V[i]]=u;
if (vis[u+V[i]]==0)
{
Q.push(u+V[i]);
vis[u+V[i]]=1;
}
}
}
while (!Q.empty());
return;
} void spfa_max()
{
memset(vis,0,sizeof(vis));
while (!Q.empty())
Q.pop();
Q.push(0);
vis[0]=1;
Dmax[0]=0; do
{
int u=Q.front();
Q.pop();
vis[u]=0; for (int i=1;i<=n;i++)
if (u+V[i]<=S)
if ((Dmax[u]+1>Dmax[u+V[i]])||(Dmax[u+V[i]]==-1))
{
Dmax[u+V[i]]=Dmax[u]+1;
path_max[u+V[i]]=u;
if (vis[u+V[i]]==0)
{
vis[u+V[i]]=1;
Q.push(u+V[i]);
}
}
}
while (!Q.empty());
return;
} void dfs_min(int sum)
{
if (sum==0)
return;
dfs_min(path_min[sum]);
cout<<Map[sum-path_min[sum]]<<' ';
return;
} void dfs_max(int sum)
{
if (sum==0)
return;
dfs_max(path_max[sum]);
cout<<Map[sum-path_max[sum]]<<' ';
return;
}

动态规划

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std; const int maxN=200;
const int maxS=200000;
const int inf=1000000000; int n,S;
int V[maxN];
int Dmin[maxS];
int Dmax[maxS];
int path_min[maxS];
int path_max[maxS];
int Map[maxS];
vector<int> arr;//输出时要临时存放面值的编号并排序 int main()
{
memset(Map,-1,sizeof(Map));
cin>>n>>S;
for (int i=1;i<=n;i++)
{
cin>>V[i];
if (Map[V[i]]==-1)
Map[V[i]]=i; }
for (int i=1;i<=S;i++)
{
Dmin[i]=inf;//初始值,最小值最大,最大值最小
Dmax[i]=-inf;
}
Dmin[0]=0;
Dmax[0]=0;
for (int i=1;i<=S;i++)
{
for (int j=1;j<=n;j++)
if (i-V[j]<0)
continue;
else//DP
{
if (Dmin[i]>Dmin[i-V[j]]+1)
{
Dmin[i]=Dmin[i-V[j]]+1;
path_min[i]=i-V[j];
}
if (Dmax[i]<Dmax[i-V[j]]+1)
{
Dmax[i]=Dmax[i-V[j]]+1;
path_max[i]=i-V[j];
}
}
} cout<<Dmin[S]<<' '<<Dmax[S]<<endl; int k=S;
arr.clear();
while (k>0)//输出方案
{
arr.push_back(Map[k-path_min[k]]);
k=path_min[k];
}
sort(arr.begin(),arr.end());
for (int i=0;i<arr.size();i++)
cout<<arr[i]<<' ';
cout<<endl; k=S;
arr.clear();
while (k>0)
{
arr.push_back(Map[k-path_max[k]]);
k=path_max[k];
}
sort(arr.begin(),arr.end());
for (int i=0;i<arr.size();i++)
cout<<arr[i]<<' ';
cout<<endl;
return 0;
}

CJOJ 1071 【Uva】硬币问题(动态规划)的更多相关文章

  1. CJOJ 2485 UVa 11991 生日礼物 / UVa 11991 Easy Problem from Rujia Liu?

    CJOJ 2485 UVa 11991 生日礼物 / UVa 11991 Easy Problem from Rujia Liu? Description (原题来自刘汝佳<训练指南>Pa ...

  2. bzoj 2017 [Usaco2009 Nov]硬币游戏 动态规划

    [Usaco2009 Nov]硬币游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 431  Solved: 240[Submit][Status] ...

  3. [bzoj1708][Usaco2007 Oct]Money奶牛的硬币_动态规划_背包dp

    Money奶牛的硬币 bzoj-1708 Usaco-2007 Oct 题目大意:在创立了她们自己的政权之后,奶牛们决定推广新的货币系统.在强烈的叛逆心理的驱使下,她们准备使用奇怪的面值.在传统的货币 ...

  4. CJOJ 1070 【Uva】嵌套矩形(动态规划 图论)

    CJOJ 1070 [Uva]嵌套矩形(动态规划 图论) Description 有 n 个矩形,每个矩形可以用两个整数 a, b 描述,表示它的长和宽.矩形 X(a, b) 可以嵌套在矩形 Y(c, ...

  5. UVa 104 - Arbitrage(Floyd动态规划)

    题目来源:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&pa ...

  6. hdu 1284 分硬币 && uva 147

    #include<bits/stdc++.h> using namespace std; int main() { unsigned ]; memset(dp,,sizeof(dp)); ...

  7. UVa 103 Stacking Boxes --- DAG上的动态规划

    UVa 103 题目大意:给定n个箱子,每个箱子有m个维度, 一个箱子可以嵌套在另一个箱子中当且仅当该箱子的所有的维度大小全部小于另一个箱子的相应维度, (注意箱子可以旋转,即箱子维度可以互换),求最 ...

  8. uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=sh ...

  9. Bzoj 1042: [HAOI2008]硬币购物 容斥原理,动态规划,背包dp

    1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1747  Solved: 1015[Submit][Stat ...

随机推荐

  1. .net Core1.0 邮件发送

    今天一天早,公司需要将之前的.net Core项目增加一个预处理机制,就是当程序出现异常后给我们的开发人员发送邮件,因为今天写些关于.netCore上发送邮件. 根据查阅资料发现在目前的Core1.0 ...

  2. 01-.Net编程机制

    .NetFarmwark特点: 多平台:该系统可以在广泛的计算机上运行,包括从服务器.桌面机到PDA和移动电话. 行业标准:该系统使用行业标准的通信协议,比如XML.HTTP.SOAP和WSDL. 安 ...

  3. vue2.0+element+node+webpack搭建的一个简单的后台管理界面

    闲聊: 今天是六一儿童节哟,小颖祝大家节日快乐哈哈哈.其实这个demo小颖断断续续做了将近两个礼拜了,心塞的,其实这个也没有多难,主要是小颖有点最近事情有点多,所以就把这个一直拖着,今天好不容易做好了 ...

  4. ECMAScript 6.0 简介

    ECMAScript 6.0 在es6中有 许多语法.还有lambda的使用.以及 class 的使用 还有一些新的对象来解决一些事情 可以提高开发效率 但更重要的是 颠覆 javascript 在你 ...

  5. qrcode生成二维码插件

    今天我要和大家分享的是利用qrcode来生成二维码. 首先要使用qrcode就需要引用文件,我这边用的是1.7.2版本的jquery加上qrcode <script type="tex ...

  6. 互联网“剁手”新方向,VR全景购物忙——全景智慧城市常诚

    随着VR和AR技术的兴起,各行各业都在寻求VR+的对接方式,除了游戏和社交平台,另一大对VR有着浓厚兴趣的就是电商平台了,阿里.京东等电商巨头纷纷成立VR事业部,如何让亿万用户在VR中愉快的买买买,已 ...

  7. 模板C++ 03图论算法 1最短路之单源最短路(SPFA)

    3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过 ...

  8. java基础(十二章)

    一.变量的作用域(有效的使用范围) 1.变量有2种 1.1成员变量(属性) 声明在类的里面,方法的外面 1.2 局部变量 声明在方法里面或for循环结构中 2.调用时的注意事项(初始值不同.作用域不同 ...

  9. 谈谈this对象

    通过平常的使用简单总结了一下不同形式的函数调用下this的指向,函数的调用形式决定了this的指向.就简单分析一下以下几种情况: 情况一:纯粹的函数调用 eg: var x=1; function f ...

  10. java实现发送邮件

    前言:先引入javamail用到的jar包, 自己下载http://fhed.v061.10000net.cn/gulili198509051s/newjspkongjian/ueditor/jsp/ ...