1. 程式人生 > >hdu 1709 求天平不能稱重的重量 動態規劃

hdu 1709 求天平不能稱重的重量 動態規劃

給定一個天平和n個砝碼,每個砝碼都有一個重量,求出從1到這些砝碼的總和之間不能被天平表示的重量。天平可以兩端放砝碼。

動態規劃做法,看網上都是母函式,真心不懂。。

dp[i]如果是0表示這些砝碼不能稱重i重量,如果是1表示能稱重i重量。

對於每個砝碼,假設當前砝碼重量是b[i],那麼j從最大值開始,減小到b[i],

如果存在一個dp[j-b[i]]為1,說明當前的j能被組成。

j逆著迴圈的原因是由於每個砝碼只有 一個,類似於01揹包與完全揹包的樣子,

如果正向迴圈會導致每個物品可能使用多次,逆向迴圈則不會出現這個問題。

其實舉個例子就能看出來了。

因為天平是可以兩邊放的,因此可以從大的數中減去小的數,方法就是對於每個砝碼重量b[i],

遍歷在dp陣列中為真的並且比b[i]那些j,那麼dp[j-b[i]]也一定為真,這個乍一看不靠譜,但經過分析好像是對的。

如果b[i]被重複使用了怎麼辦?即dp[j]已經使用了b[i]了,你還要減去b[i],但它只有一個啊。

此時如果dp[j]已經使用了b[i],那麼dp[j-b[i]]早已經為真了,即由別的砝碼早可以組成dp[j-b[i]]了。

如果是多個砝碼減2個砝碼怎麼辦?不會漏掉嗎?其實在第一個砝碼的時候就記錄了多個砝碼減第一個砝碼的結果,

到第二個砝碼的時候會用到這個結果。這樣就不會漏了。

其實這也是dp,這個dp的j要正向進行,逆向進行就會導致砝碼重複使用。

#include<bitset>
#include<map>
#include<vector>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<stack>
#include<queue>
#include<set>
#define inf 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

inline int in()
{
    int res=0;
    char c;
    while((c=getchar())<'0' || c>'9');
    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();
    return res;
}

const int N=100006;
int dp[N];    //注意要大一些, 因為範圍是砝碼的總和
int b[2006];

int ans[20000];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        mem(dp,0);
        int mx=0;
        for(int i=0;i<n;i++)
        {
            b[i]=in();
            mx+=b[i];
        }

        dp[0]=1;
        for(int i=0;i<n;i++)
        {
            for(int j=mx;j>=b[i];j--)
            {
                if(dp[j-b[i]]) dp[j]=1;
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=b[i];j<=mx;j++)
            {
                if(dp[j])dp[j-b[i]]=1;  //每個比當前砝碼大的,減去當前砝碼的重量。
            }
        }
        int p=0;
        for(int i=1;i<=mx;i++)if(!dp[i])ans[p++]=i;
        printf("%d\n",p);
        for(int i=0;i<p-1;i++)
        {
            printf("%d ",ans[i]);
        }
        if(p>0)printf("%d\n",ans[p-1]);  //當時又漏了p>0


    }
    return 0;
}


相關推薦

hdu 1709 天平不能重量 動態規劃

給定一個天平和n個砝碼,每個砝碼都有一個重量,求出從1到這些砝碼的總和之間不能被天平表示的重量。天平可以兩端放砝碼。 動態規劃做法,看網上都是母函式,真心不懂。。 dp[i]如果是0表示這些砝碼不能稱重i重量,如果是1表示能稱重i重量。 對於每個砝碼,假設當前砝碼重量是b

砝碼 5個砝碼 用天平時,我們希望用盡可能少的砝碼組合稱出儘可能多的重量

/*砝碼稱重 5個砝碼 用天平稱重時,我們希望用盡可能少的砝碼組合稱出儘可能多的重量。 如果只有5個砝碼,重量分別是1,3,9,27,81。則它們可以組合稱出1到121之間任意整數重量(砝碼允許放在左

使用天平,經驗證,用四個砝碼可以秤出1~40的全部整數重量,請問是哪四個砝碼?

這個在數學上叫做梅氏砝碼問題,其敘述如下: 若有n個砝碼,重量分別為M1,M2,……,Mn,且能稱出從1到(M1+M2+……+Mn)的所有重量,則再加一個砝碼,重量為Mn+1=(M1+M2+……+M

枚舉 天平

font strong 所有 rst 輸出 color iostream algorithm pan 天平稱重 【問題描述】 用天平稱重時,我們希望用盡可能少的砝碼組合稱出盡可能多的重量。 如果只有5個砝碼,重量分別是1,3,9,27,81 則它們可以組合稱出1

【數學】天平

用天平稱重時,我們希望用盡可能少的砝碼組合稱出儘可能多的重量。如果只有5個砝碼,重量分別是1,3,9,27,81則它們可以組合稱出1到121之間任意整數重量(砝碼允許放在左右兩個盤中)。本題目要求程式設計實現:對使用者給定的重量,給出砝碼組合方案。例如:使用者輸入:5程式輸出

巧用三進位制解決天平問題

1.問題描述:  用天平稱重時,我們希望用盡可能少的砝碼組合稱出儘可能多的重量。  如果有無限個砝碼,但它們的重量分別是1,3,9,27,81,……等3的指數冪  神奇之處在於用它們的組合可以稱出任意整數重量(砝碼允許放在左右兩個盤中)。  本題目要求程式設計實現:對使用者給

【進位制轉換】天平

用天平稱重時,我們希望用盡可能少的砝碼組合稱出儘可能多的重量。如果只有5個砝碼,重量分別是1,3,9,27,81則它們可以組合稱出1到121之間任意整數重量(砝碼允許放在左右兩個盤中)。本題目要求程式設計實現:對使用者給定的重量,給出砝碼組合方案。例如:使用者輸入:5程式輸出

筆試面試題 —— 天平與二進位制

有人曾問帳前卒一道題:至少需要多少個砝碼,才能稱出1~50g物體?這道題有兩個變種: 1.至少需要多少砝碼(左物右碼),才能稱出1~50g物體?2.至少需要多少砝碼(砝碼可以放在任意一邊),才能稱出1~50g物體?第一問可以變為: 至少多少個數字相加,可以表示1~50之間的任

hdu-1231 連續最大子序列(動態規劃

得到 繼續 用例 using 規劃 mem 空格 編寫 序號 Time limit1000 ms Memory limit32768 kB 給定K個整數的序列{ N1, N2, ..., NK },其任意連續子序列可表示為{ Ni, Ni+1, ..., Nj },其中

Dijkstra演算法,最短路(dp 動態規劃

•迪傑斯特拉(Dijkstra)演算法思想 按路徑長度遞增次序產生最短路徑演算法: 把V分成兩組: (1)S:已求出最短路徑的頂點的集合 (2)V-S=T:尚未確定最短路徑的頂點集合 將T中頂點按最短路徑遞增的次序加入到S中, 保證:(1)從源點V0到S中各

LeetCode -- Triangle 路徑最小和( 動態規劃問題)

Given a triangle, find the minimum path sum from top to bottom.  Each step you may move to adjacent numbers on the row below. For example, given the foll

POJ 1458/HDU 1159 最長公共子序列 (動態規劃)

題目連結:poj && hdu 程式碼 #include <iostream> #include <cstdio> #include <algo

HDU 6331 Walking Plan(分塊 動態規劃

題意 給一個 nn 個節點 mm 條邊的有向圖,第 ii 條邊的兩個端點為 ui,viui,vi,邊的長度為 wiwi,qq 次詢問,每次詢問從節點 ss 到 tt 至少走過 kk 條路徑的最小距離。 輸入 第一行包含一個整數 T(1

hdu 1024 Max Sum Plus Plus(動態規劃+m子段和的最大值)

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you ar

101個硬幣100真、1假,真假區別在於重量。請用無砝碼天平兩次給出真幣還是假幣的結論。

把101個硬幣分成三堆,倆堆50個,和另外一個 一,稱倆堆50個,如果重量相等。 則說明假幣是那單獨的一個        隨便取一個真幣和這個假幣做比較,即可得出哪個硬幣更重 如果重量不相等,說明剩下那個硬幣是真的,然後倆堆50個裡面有一個必然是假的,同時天平不平衡。 用一個

個人小專案:現有12個小球和一個天平,小球中有一個重量與其它的不同,幾次能將這個小球找出來

<script language="JavaScript"> //建立兩個陣列,分別存放左邊盤小球物件和右邊盤小球物件 var leftbar = new Array(); var rightbar = new Array(); //建立一個整形變數,存放當前稱重的次數

HDU acm 1003 Max Sum || 動態規劃最大子序列和詳解

line namespace num more sequence mem ould 動態規劃 ger Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot

HDU - 2087 不可復字符串的匹配次數

break mar blog cpp cnblogs markdown 重復 字符 body 只要KMP裏對f[i]進行限制即可 /*H E A D*/ int nxt[maxn],f[maxn],ans; char T[maxn],P[maxn]; void buildN

12個球用天平3次找到重量不同的那個球

將12個球分成3組,每4個一組 1  將4個A放到天平左邊,4個B放到天平右邊;可能出現2種情況: a:平衡 b:不平衡 1.1 如果是a 情形  說明在天平上的八個球都是普通球,而剩下的4個球裡面有一個是特殊球,我們把不知道的球記為 X ,普通球記為 Y,那麼現在有4個X

動態規劃---砝碼問題

一、演算法分析 動態規劃(Dynamic Programming)這個詞乍一聽感覺甚是高大上,初次學習或者使用的時候會感覺難以理解,這是正常的,畢竟凡事都是一回生二回熟。其實它也不難的,大家要明白一個道理,能寫到課本上給學生學習的東西必然屬於不難的東西,因為太難的東西寫