題意:有n(n<=1000)個紙牌,每個紙牌分為上下兩格,且每格可有1-10個點,所有上格加起來的和為p1,所有下格加起來的和為p2,求想得到|p1-p2|的最小值,需要翻轉多少次
給出的題解是:
正常的做法是用 dp,可以用二維的 dp 陣列,在這里用了一維陣列進行 dp。 dp[i] 表示上下相差為i 時的最小操作次數。 因為是上下相差所以可能出現負數,將整個陣列右移 位, 理論上是上下相差的最大值 在實際程式中 dp[i+n] 是上面 dp[i] 所表示的意義
每次翻轉會使上下差值改變,這個改變值記錄為 a[j],改變值應該是初始值的兩倍。 狀態轉移方程就是 dp[i-a[j]]=min(dp[i-a[j]],dp[i]+1) 同時又考慮到差值有負數的情況,所以根據初始差值情況分類討論一下,不同情況dp的方向 不同。
最後在 dp 陣列中從 n 向兩側尋找能達到的最小值輸出即可。
二維的**也很好懂
#includeusingnamespace
std;
int dp[1005][20005
];int a[1005
];const
static
int inf=0x7fffff
;int
main()
int t=tx-ty;
int n=1000
;
for(int i=0;i<=1000;i++)
for(int j=0;j<=20000;j++)
dp[i][j]=inf;
dp[0][t+n]=0
;
for(int i=1;i<=n;i++)}}
intans;
for(int i=0;i<=1000;i++)
}cout
<}
但在轉換成一維的時候遇到不少問題,花了很多時間,第乙個點在於一維的時候為了考慮a[i]的正負,還需要分情況討論
第二個點在於分情況討論後其狀態轉移方程還是得一致
#includeusingnamespace
std;
typedef
long
long
ll;const
int inf=1
<<30
;const
int maxn=1e3+7
;int
a[maxn];
int dp[20010];//
上下差為i(此時陣列內數為10000+i)時的最小操作次數
intmain()
int t=tx-ty;
for(int i=0;i<=20000;i++)dp[i]=inf;
dp[1000+t]=0;//
初始狀態
for(int i=1;i<=n;i++)
}else
for(int j=20000;j>=a[i];j--)
}intans;
for(int i=0;i<=1000;i++)
} cout
return0;
}
揹包 DP 揹包
揹包 題目 是dp中較為常見的題目 分為 0 1 揹包 完全揹包 和多重揹包 這三類 是越來越深入的首先來介紹一下 0 1揹包 首先 0 1 揹包的含義是 給你乙個容量位m的揹包 然後給你n個物品 每個物品具有一定價值和一定重量 會站一定的揹包空間 答案是在n個物品中那幾個 然後使得到的價值最大 首...
簡單的煩惱 揹包問題
第一行乙個整數t t 23 表示資料組數。在每組輸入資料中,第一行有兩個正整數,n n 200 t t 80000 分別表示歌單中歌曲的數目,和題目描述中的t。第二行中有n個正整數a i a i 400 表示每首歌曲的時間長度。對於每組資料,輸出乙個ans,表示最多能聽多長時間的歌曲。示例1 複製1...
揹包dp之01揹包
現在我們有n個配件,他們有不同的價值.但是我們揹包的容量是有限的,因為我們只有乙個一級包,所以我們最多可以裝v重量的東西.但是為了能更好的吃到雞 不存在的 我們要攜帶更有價值的配件,請問我們最多能拿多少價值的配件來當快遞員呢?輸入的第一行是t,表示有一共要打t場比賽.每組資料由三行組成.第一行包含兩...