Each input file contains one test case. For each case, the first line contains 2 positive numbers: N (<=104, the total number of coins) and M(<=102, the amount of money Eva has to pay). The second line contains N face values of the coins, which are all positive numbers. All the numbers in a line are separated by a space.
For each test case, print in one line the face values V1 <= V2 <= ... <= Vk such that V1 + V2 + ... + Vk = M. All the numbers must be separated by a space, and there must be no extra space at the end of the line. If such a solution is not unique, output the smallest sequence. If there is no solution, output "No Solution" instead.
Note: sequence {A[1], A[2], ...} is said to be "smaller" than sequence {B[1], B[2], ...} if there exists k >= 1 such that A[i]=B[i] for all i < k, and A[k] < B[k].
8 9 5 9 8 7 2 3 4 1
1 3 5
优雅解决#include <bits/stdc++.h> using namespace std; int a[10100],b[110]; vector<int> dp[110]; int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); dp[0].push_back(0); for(int i=n-1;i>=0;i--){ //倒序保证字典需最小 for(int j=m;j>=a[i];j--){ if(dp[j-a[i]].size()!=0){dp[j]=dp[j-a[i]];dp[j].push_back(a[i]);} } } if(dp[m].size()==0)printf("No Solution\n"); else{ for(int i=dp[m].size()-1;i>=1;i--)printf("%d ",dp[m][i]); } return0; }
/*注意到只有100,直接dfs,当然也可以按照装满背包做*/ #include <bits/stdc++.h> using namespace std; int n , k , x , f ; vector<int>res,tmp; map<int,int>mp; void dfs( int m ) { if( f ) return ; if( !m ) { f = 1 ; res = tmp ; return ; } for( auto i : mp ) { if( i.second ) { if( m >= i.first ) { mp[i.first] --; tmp.push_back(i.first); dfs( m - i.first ); tmp.pop_back(); mp[i.first] ++; } } } } int main() { scanf("%d%d",&n,&k); for( int i = 0 ; i < n ; i++ ) { scanf("%d",&x); if( x <= k ) mp[x] ++ ; } f = 0 ; dfs(k); if( !res.size() ) return 0*printf("No Solution"); int len = res.size(); for( int i = 0 ; i < len ; i++ ){ printf("%d",res[i]); if( i != len - 1 ) printf(" "); } return 0 ; }
//题目解析来自@cheerss https://www.jianshu.com/p/20dac38241a5 //这是一道01背包问题,解题时注意题意的转化:可以将每个coin都看成value和weight都相同的物品
//1. 要求所付的钱刚刚好,相当于要求背包必须刚好塞满,且价值最大。
// (限制背包体积相当于限制coin的总和不能超过所要付的钱,在此条件下求coin组合的最大值,
// 如果这个最大值刚好等于要付的钱,则有解,此时背包也刚好处于塞满状态,否则无解)
//2. 最后要求从小到大输出coin的组合,且有多解时输出最小的组合。
// 我们应该将coin从大到小排序,在放进背包时也从大到小逐个检查物品,更新背包价值的条件是在加入一个新的物品后,价值>=原价值,
// 由于物品是从大到小排序的,如果一个新的物品的加入可以保证价值和原来相同,则此时一定是发现了更小的组合。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=10010;
const int maxv=110;
int w[maxn],dp[maxv]={0}; //w[]为钱币的价值
bool choice[maxn][maxv]; //choice[i][j]表示计算dp[i][j]时是否选择了i物品
vector<int> ans;
bool cmp(int a,int b){
return a>b;
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i];
sort(w+1,w+n+1,cmp); //从大到小排序(以求得字典序最小的情况)
for(int i=1;i<=n;i++){ //逆序遍历(dp[i][j]只与dp[i-1][j]和dp[i-1][j-w[i]]有关,即只和i-1时刻状态有关);下边界w[i],因为j<w[i]使得j-w[i]为负数无意义
for(int j=m;j>=w[i];j--){ //如果正序遍历则当求dp[v]时其前面的dp[0],dp[1],…,dp[j-1]都已经改变过,里面存的都不是i-1时刻的值,这样求dp[j]时利用dp[j-w[i]]必定是错的值。
if(dp[j]<=dp[j-w[i]]+w[i]){ //等于号也要取(如果一个新的物品的加入可以保证价值和原来相同,则此时一定是发现了更小的组合。)
dp[j]=dp[j-w[i]]+w[i];
choice[i][j]=true; //放入第i件物品
}
else choice[i][j]=false;
}
}
if(dp[m]!=m) cout<<"No Solution"; //无解(本题容量与价值合二为一),刚好塞满背包容量即等于最大价值
else{
int v=m,index=n;
while(v>0){ //从后往前寻找输出路径(得到之前修改dp[]时的选择物品情况),从后往前是因为物品价值从大到小排列,而输出要从小到大
if(choice[index][v]==true){
ans.push_back(w[index]);
v-=w[index];
}
index--;
}
for(int i=0;i<ans.size();i++){
if(i!=0) cout<<" ";
cout<<ans[i];
}
}
return 0;
}
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
int mark[10010];
vector<int> finalresult;
void dfs2(vector<int> input,int index,int sum,int M)
{
if(sum>M||index>input.size()-1||input[index]>M)
return;
if(sum==M&&finalresult.size()==0)
{
for(int i=0;i<input.size();i++)
{
if(mark[i]>0)
finalresult.push_back(input[i]);
}
return;
}
mark[index]++;
dfs2(input,index+1,sum+input[index],M);
mark[index]--;
dfs2(input,index+1,sum,M);
}
int main()
{
memset(mark,0,sizeof(mark));
vector<int> input;
int N,M;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
int tmp;
scanf("%d",&tmp);
input.push_back(tmp);
}
sort(input.begin(),input.end());
if(input.size()==1&&M==input[0])
{
cout<<M<<endl;
return 0;
}
dfs2(input,0,0,M);
if(finalresult.size()==0)
cout<<"No Solution";
else
{
for(int i=0;i<finalresult.size();i++)
{
cout<<finalresult[i];
if(i!=finalresult.size()-1)
{
cout<<" ";
}
}
}
cout<<endl;
return 0;
}
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 10010; const int MAXV = 103; int w[MAXN],dp[MAXV]={0}; bool choice[MAXN][MAXV],flag[MAXN]; bool cmp(int a, int b) { return a>b; } int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) cin>>w[i]; sort(w+1,w+n+1,cmp); for(int i=1;i<=n;i++) { for(int j=m;j>=w[i];j--) { if(dp[j] <= dp[j-w[i]] + w[i]) { dp[j] = dp[j-w[i]] + w[i]; choice[i][j] = true; }else choice[i][j] = false; } } if(dp[m] != m) cout<<"No Solution\n"; else{ int k=n,num=0,v=m; while(k>=0) { if(choice[k][v] == true) { flag[k] = true; v -= w[k]; num++; }else flag[k] = false; k--; } for(int i=n;i>=1;i--) { if(flag[i] == true) { cout<<w[i]; num--; if(num>0) cout<<" "; } } cout<<endl; } return 0; }
import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); int[] coins = new int[n]; for(int i = 0;i<n;i++) coins[i] = in.nextInt(); Arrays.sort(coins); int[] result = new int[n]; int j = find(coins, 0, result, 0, m); if(j<0){ System.out.println("No Solution"); }else{ for(int i = 0;i<j;i++) System.out.print(result[i]+" "); System.out.println(result[j]); } } private static int find(int[] coins,int start,int[] result,int j,int m){ for(int i = start;i<coins.length;i++){ if(coins[i]<m){ //当前位置符合 找下一个位置 result[j] = coins[i]; int flag = find(coins, i+1, result, j+1, m-coins[i]); if(flag!=j) return flag; result[j] = 0; }else if(coins[i]==m){ result[j] = coins[i]; return j; }else return j-1; } return j-1; } }
#include <algorithm> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <vector> using namespace std; typedef pair<int, int> P; typedef long long ll; const int N = 1e4 + 5; const int M = 105; int n, m; int coins[N]; bool dp[M]; vector<int> G[M]; bool cmp(int x, int y) { return y < x; } int main() { #ifdef LOCAL freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif cin >> n >> m; for (int i = 1; i <= n; i++) cin >> coins[i]; sort(coins + 1, coins + n + 1, cmp); dp[0] = true; for (int i = 1; i <= n; i++) { for (int j = m; j >= 0; j--) { if (j >= coins[i]) { dp[j] |= dp[j - coins[i]]; if (dp[j - coins[i]]) { G[j].clear(); for (int val : G[j - coins[i]]) G[j].push_back(val); G[j].push_back(coins[i]); } } } } if (dp[m]) { reverse(G[m].begin(), G[m].end()); for (int val : G[m]) cout << val << ' '; } else puts("No Solution"); return 0; }
#include<bits/stdc++.h> using namespace std; const int maxn=1e4+1; int n,m,value[maxn],dp[101]; bool choice[maxn][101]; //dp[i][j]:前i件物品容量为j时的最大价值 //本题重量=价值,最终判断dp[n][m]==m即可,固定容量为m,前n件物品的最大价值是否达到m void DP(){ sort(value+1,value+n+1,greater<int>()); //背包问题初始化 dp[0][j]=0 for(int i=1;i<=n;i++){ //1维dp,倒着枚举容量 for(int j=m;j>=value[i];j--){ if(dp[j-value[i]]+value[i]>=dp[j]){ dp[j]=dp[j-value[i]]+value[i]; choice[i][j]=true; }else{ choice[i][j]=false; } } } } int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>value[i]; DP(); if(dp[m]!=m){ cout<<"No Solution"; return 0; } int k=n,v=m;//物品编号,容量 while(v!=0){ if(choice[k][v]){ cout<<value[k]; v-=value[k]; if(v!=0) cout<<" "; } k--; } return 0; }
#include<cstdio> int a[101] = { 0 }, b[101] = { 0 }; int n, m, z; bool dfs(int i, int amo) { while (a[i] == 0 && i < 101) i++; if (i > 100) return false; for (int j = a[i]; j >= 0; j--) { if (amo == i*j) { z = i; b[i] = j; return true; } else if (amo > i*j) { if (dfs(i + 1, amo - i*j)) { b[i] = j; return true; } } } return false; } int main() { int t; scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%d", &t); if (t < 101) a[t]++; } if (dfs(1, m)) { for (int i = 1; i < z; i++) { if (b[i]) { while (b[i]--) { printf("%d ", i); } } } while (--b[z]) printf("%d ", z); printf("%d", z); } else printf("No Solution"); return 0; }
#include<iostream> (720)#include<vector> #include<algorithm> //1 2 3 4 5 7 8 9 using namespace std; int N, M,x; vector<int>coins(N); bool dfs(vector<int>vec, int i) { int sum = 0; for (int k = 0; k < vec.size(); k++) { sum += vec[k]; } if (sum == M) {//第一次就是最小的 for (int k = 0; k < vec.size(); k++) { if (k) printf(" "); printf("%d", vec[k]); } return true; } else if (sum < M) { for (int j = i; j < N; j++) { vector<int>tmp; /*for (int k = 0; k < vec.size(); k++) { tmp.push_back(vec[k]); }*/ tmp = vec; tmp.push_back(coins[j]); bool flag=dfs(tmp, j + 1); if (flag) { return true; } } } return false; } int main() { cin >> N >> M; for (int i = 0; i < N; i++) { cin >>x; coins.push_back(x); } sort(coins.begin(), coins.end()); vector<int>ans; bool ff=dfs(ans, 0); if (!ff) { printf("No Solution"); } }
a = list(map(int,input().split(' '))) b = sorted(list(map(int,input().split(' '))),reverse = True) i = 0;q = a[1];p = 0;c = '';e = '' while i < len(b): if b[i] == q: c = e + chr(b[i] + 48);f = 1;i += 1 elif b[i] < q: j = a[0] - 1 - p while i - j: if b[i] + b[j] < q:j -= 1 # 一级副光标 elif b[i] + b[j] > q:i += 1 # 一级主光标 else:break else:break m = a[0] - 1 - p;n = j;r = b[j] while m - n > 0: if b[m] + b[n] < r:m -= 1 # 二级副光标 elif b[m] + b[n] > r:n += 1 # 二级主光标 else: e += chr(b[m] + 48);b.remove(b[m]) p += 1;r = b[n];m = a[0] - 1 - p;n += 1;continue else:e += chr(r + 48);b.remove(r);p += 1;q = b[i] else:i += 1 if c: c = list(map(lambda x:x - 48,map(ord,sorted(c))));i = 0 while i < len(c) - 1: if c[i] > b[-1]: for j in range(-2,-len(b),-1): if c[i] + c[-1] == b[-1] + b[j]: c.append(b[-1]);c.append(b[j]);del b[-1];del b[j] b.append(c[-1]);b.append(c[i]);del c[-3];del c[i] b = sorted(b,reverse = True);c = sorted(c);break i += 1 print(' '.join(map(str,c))) else: print('No Solution')
@author 孙荣达
*/
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer tokenizer; tokenizer=new StringTokenizer(reader.readLine()); int n = Integer.parseInt(tokenizer.nextToken()); int m=Integer.parseInt(tokenizer.nextToken()); tokenizer=new StringTokenizer(reader.readLine()); int []num=new int[n]; int temp; for(int i=0;i<n;i++) { num[i]=Integer.parseInt(tokenizer.nextToken()); } Arrays.sort(num); boolean [][]can=new boolean[10002][102];
can[n][0] = true; for (int i = n - 1; i >= 0; --i) { for (int j = 0;j <= m; ++j) { can[i][j] = can[i + 1][j] || ((j >= num[i]) && can[i + 1][j - num[i]]); } } for(int i=0;i<n;i++) { for(int j=0;j<=m;j++) { System.out.print(can[i][j]+" "); } System.out.println(); } if (can[0][m]) { boolean have = false; for (int i = 0; (i < n) && (m >= num[i]); ++i) { if (can[i + 1][m - num[i]]) { if (have) { System.out.print(" "); } else { have = true; } System.out.print(num[i]); m -= num[i]; } } //puts(""); } else { System.out.println("No Solution"); } }
}
N,M=map(int,input().split())
c=list(map(int,input().split()))
c.sort()
F=[None]*(M+1)
F[0]=[]
for i in range(N):
for j in range(M,coin[i]-1,-1):
t=F[j-c[i]][:]+[c[i]] if F[j-c[i]]!=None else None
F[j]=F[j] if t==None else t if F[j]==None else min(F[j],t)
if F[M]!=None:
print(' '.join(map(str,F[M])))
else:
print('No Solution')
难过,难过,难过import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; public class Main { private static int m; public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); m = in.nextInt(); int[] money = new int[n]; for (int i = 0; i < n; i++) money[i] = in.nextInt(); Arrays.sort(money); ArrayList<ArrayList<Integer>> result = new ArrayList<>(); ArrayList<Integer> subList = new ArrayList<>(); back(result, subList, money, 0, 0); if (result.size() == 0) System.out.println("No Solution"); else { List<Integer> res = result.get(0); for (int i = 0; i < res.size() - 1; i++) System.out.print(res.get(i) + " "); System.out.println(res.get(res.size() - 1)); } } private static boolean flag; public static void back(ArrayList<ArrayList<Integer>> result, ArrayList<Integer> subList, int[] arr, int start, int sum) { if (flag) return; if (start > arr.length || sum > m) return; if (sum == m) { flag = true; result.add(new ArrayList<>(subList)); return; } for (int i = start; i < arr.length; i++) { subList.add(arr[i]); back(result, subList, arr, i + 1, sum + arr[i]); subList.remove(subList.size() - 1); if (sum + arr[i] > m) break; } } }回溯算法,好像没看到有人用贴出来分享一下。
深度优先搜索#include<iostream>#include<vector>#include<algorithm>using namespace std;vector<int> last;void dfs(vector<vector<int>> &result,int target,vector<int> path,int length,int start,vector<int> &number){if(length==target){result.push_back(path);return;}if(length>target)return;if(target-length>last[start])return;for(int i=start+1;i<number.size();i++){if(number[i]+length>target)break;path.push_back(number[i]);dfs(result,target,path,length+number[i],i,number);if(result.size()>0)break;path.pop_back();}}int main(){int n;int m;cin>>n>>m;vector<int> number;for(int i=0;i<n;i++){int temp;cin>>temp;number.push_back(temp);}sort(number.begin(),number.end());int sum=0;last=vector<int>(n,0);for(int i=number.size()-1;i>=0;i--){last[i]=sum;sum+=number[i];}vector<vector<int>> result;for(int i=0;i<number.size();i++){if(number[i]>m)continue;vector<int> path;path.push_back(number[i]);dfs(result,m,path,number[i],i,number);if(result.size()>0)break;}if(result.size()==0){cout<<"No Solution";}else{vector<int> v=result[0];for(int i=0;i<v.size()-1;i++){cout<<v[i]<<" ";}cout<<v.back();}return 0;}
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 10001; const int maxv = 101; int w[maxn], dp[maxv] = {0}; bool choice[maxn][maxv], flag[maxn]; bool compare(int a, int b){ return a > b; } int main(){ int n, m; scanf("%d %d", &n, &m); for(int i=1; i<=n; i++) scanf("%d", &w[i]); sort(w + 1, w + n + 1, compare); for(int i=1; i<=n; i++){ for(int v=m; v>=w[i]; v--){ if(dp[v] <= dp[v-w[i]] + w[i]){ dp[v] = dp[v-w[i]] + w[i]; choice[i][v] = true; } else choice[i][v] = false; } } if(dp[m] != m) printf("No Solution\n"); else{ int k = n, num = 0, v=m; while(k >= 0){ if(choice[k][v] == true){ flag[k] = true; v -= w[k]; num ++; } else flag[k] = false; k--; } for(int i=n; i>=1; i--){ if(flag[i] == true){ printf("%d", w[i]); num --; if(num > 0) printf(" "); } } printf("\n"); } return 0; }
}
//这题用0-1背包问题,不过用硬币的组合替换了原来背包问题的权值
/*
动态规划举例:
8 9
5 9 8 7 2 3 4 1
先排序,然后依次处理1,2,3,4...
和:0 1 2 3 4 5 6 7 8 9
组成方法:
处理1
序号 0 1 2 3 4 5 6 7 8 9
dp () (1) () () () () () () () ()
处理2
序号 0 1 2 3 4 5 6 7 8 9
dp () (1) (2) (1,2) () () () () () ()
更新序号i时根据序号i-2,i-2存在则有dp[i-2].push_back(2)的组成方式
然后看看这种方式是否最优,是则加到dp[i],下面同理
处理3
序号 0 1 2 3 4 5 6 7 8 9
dp () (1) (2) (1,2) (1,3) (2,3) (1,2,3) () () ()
....
另外遍历j时是倒序的,跟新i是需要上个硬币的dp[i-2],正序dp[i-2]被更新为
这个硬币的了
*/
#include<bits/stdc++.h>
using namespace std;
//
vector<int> MySmall(vector<int> &a, vector<int> &b){
//空的返回另一一个
if(a.empty())return b;
if(b.empty())return a;
int p = 0;
while (p < a.size() && p < b.size()){
if (a[p] < b[p])return a;
if (a[p] > b[p])return b;
p++;
}
return a.size()>b.size() ? a : b;
}
int main(){
ios::sync_with_stdio(false);
int N, M;
vector<int> v;
cin >> N >> M;
v.resize(N);
for (int i = 0; i<N; i++){
cin >> v[i];
}
sort(v.begin(), v.end());
vector<vector<int>> dp(M+1);//dp[j]:和j的最small的组合
for (int i = 0; i < N;i++){
int n = v[i];
for (int j = M; j >= n; j--){
vector<int> tmp = dp[j - n];
tmp.push_back(n);
if (tmp.size() > 1 || n == j){
dp[j] = MySmall(dp[j], tmp);
}
}
}
if (dp[M].empty()){
cout << "No Solution";
}
else{
for (int i = 0; i<dp[M].size() - 1; i++){
cout << dp[M][i] << " ";
}
cout << dp[M].back();
}
return 0;
}