POJ 1252 Euro Efficiency(最短路 完全背包)

题意:

给定6个硬币的币值, 问组成1~100这些数最少要几个硬币, 比如给定1 2 5 10 20 50, 组成40 可以是 20 + 20, 也可以是 50 -10, 最少硬币是2个。

分析:

这道题可以转化成是一道最短路的方法去做, 设一开始的起点为0(什么硬币都不取), 然后每个点都有12条路(对应正负6种币值), 每条路的权值为1,

令dis[maxn]初始化为inf, 求出dis[1]~dis[100]即可。

但是最大值maxn要取比100更大, 比如 构造100的最优方法为51+51-1-1. 那么我们就需要102面值金钱的构造dist[102] 才能正确的推出dist[100], 虽然不知道这个最大值多少,但这个最大值取200可以过这题。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <queue>
 4 #include <cstring>
 5 #define mem(a) memset(a, 0, sizeof(a))
 6 using namespace std;
 7 const int maxn = 207;
 8 const int inf = 1e9;
 9 int coin[12];
10 int dis[maxn];
11 int vis[maxn];
12 void spfa(){
13     mem(vis);
14     queue<int> q;
15     fill(dis,dis+maxn, inf);
16     dis[0] = 0;
17     vis[0] = 1;
18     q.push(0);
19     while(!q.empty()){
20         int u = q.front();
21         for(int i = 0; i < 12; i++){
22             int v = u + coin[i];
23             if(v < 0 || v > 200) continue;//如果点v是负数, 那么不需要入队。
24             if(dis[v] > dis[u] + 1){
25                 dis[v] = dis[u] + 1;
26                 if(!vis[v]){
27                     vis[v] = 1;
28                     q.push(v);
29                 }
30             }
31         }
32 //        vis[u] = 0; 这里其实不用标记, 因为每个点只会入队一次,边的权值都是1, 怎么扩展都是最短路
33         q.pop();
34     }
35 }
36 int main()
37 {
38     int t;
39     cin >> t;
40     while ( t -- ) {
41         for ( int i = 0 ; i < 6 ; ++ i ){
42             cin >> coin[ 2*i ];
43             coin[2 * i + 1] = -coin[2 * i];//构造币值为负数的硬币
44         }
45         spfa();
46         double sum = 0.0;
47         int    maxdis = 0;
48         for ( int i = 1 ; i <= 100  ; ++ i ) {
49             sum += dis [i];
50             if ( dis[i] > maxdis )
51             maxdis = dis[i];
52         }
53         printf("%.2f %d
",sum/100.0, maxdis);
54     }
55     return 0;
56 }
原文地址:https://www.cnblogs.com/Jadon97/p/8330101.html