我好像離上次寫blog有1個月了吧,想想現在太浪了,寫篇題解壓壓驚σ( ° △ °|||)︴。
2023年9月11日,一場突發的災難將紐約世界**中心大廈夷為平地,mr. f曾親眼目睹了這次災難。為了紀念「9?11」事件,mr. f決定自己用水晶來搭建一座雙塔。
mr. f有n塊水晶,每塊水晶有乙個高度,他想用這n塊水晶搭建兩座有同樣高度的塔,使他們成為一座雙塔,mr. f可以從這n塊水晶中任取m(1≤m≤n)塊來搭建。但是他不知道能否使兩座塔有同樣的高度,也不知道如果能搭建成一座雙塔,這座雙塔的最大高度是多少。所以他來請你幫忙。
給定水晶的數量n(1≤n≤100)和每塊水晶的高度hi(n塊水晶高度的總和不超過2000),你的任務是判斷mr. f能否用這些水晶搭建成一座雙塔(兩座塔有同樣的高度),如果能,則輸出所能搭建的雙塔的最大高度,否則輸出「impossible」。
輸入的第一行為乙個數n,表示水晶的數量。第二行為n個數,第i個數表示第i個水晶的高度。
輸出僅包含一行,如果能搭成一座雙塔,則輸出雙塔的最大高度,否則輸出乙個字串「impossible」。
5
1 3 4 5 2
7
某校noip模擬題
這題非常有意思,
大暴力肯定是不行的,這裡有明顯的重疊子問題,我們可以試試看動態規劃,
首先,我們確定一下它的最優子結構,
f[i][j][k]表示前i個積木是否能有一塔為j,另一塔為k的情況。
轉移非常好寫(這裡就不寫了),並且我們可以用揹包的思想乾掉一維,
**:
1 #include2 #include3 #include4 #include5 #include6 #include7 #include8view codeusing
namespace
std;
9 typedef long
long
ll;10 typedef long
double
ld;11 typedef pairpr;
12const
double pi=acos(-1
);13
#define rep(i,a,n) for(int i=a;i<=n;i++)
14#define per(i,n,a) for(int i=n;i>=a;i--)
15#define rep(i,u) for(int i=head[u];i;i=next[i])
16#define clr(a) memset(a,0,sizeof(a))
17#define pb push_back
18#define mp make_pair
19#define fi first
20#define sc second
21#define pq priority_queue
22#define pqb priority_queue , less>
23#define pqs priority_queue , greater>
24#define vec vector
25 ld eps=1e-9
;26 ll pp=1000000007
;27 ll mo(ll a,ll pp)
28 ll powmod(ll a,ll b,ll pp)
29void fre()
30//
void add(int x,int y,int z)
31int dx[5]=,dy[5]=;
32 ll read()
37const
int n=2005;38
intf[n][n],a[n],sum;
39int
main()
4048
for (int i=sum;i>=1;i--)
49if
(f[i][i])
53 printf("
impossible");
54return0;
55 }
時間複雜度:sum^2*n;
肯定是過不了的,但資料水一不小心就過了(霧)。
想到這裡我們有沒有感覺最後一位只存0/1有點浪費。
於是乎,
f[i][j]表示前i個積木一塔為j的離他最近的塔的高度。
可是很氣的是這不是乙個最優子結構,(反例自己找),
陷入了沉思,
用一塔的高度做狀態不行,那差呢》?
f[i][j]表示前i個積木差為i的最矮的塔高。
試試看轉移:
f[i][j]=max(f[i][j],f[i-1][j]);
f[i][j]=max(f[i][j],f[i-1][j+a[i]]+a[i]);
if (j>=a[i]) f[i][j]=max(f[i][j],f[i-1][j-a[i]]);
else f[i][j]=max(f[i][j],f[i-1][a[i]-j]+a[i]-j);
非常好,就有滿足了條件,
**:
1 #include2 #include3 #include4 #include5 #include6 #include7 #include8view codeusing
namespace
std;
9 typedef long
long
ll;10 typedef long
double
ld;11 typedef pairpr;
12const
double pi=acos(-1
);13
#define rep(i,a,n) for(int i=a;i<=n;i++)
14#define per(i,n,a) for(int i=n;i>=a;i--)
15#define rep(i,u) for(int i=head[u];i;i=next[i])
16#define clr(a) memset(a,0,sizeof(a))
17#define pb push_back
18#define mp make_pair
19#define fi first
20#define sc second
21#define pq priority_queue
22#define pqb priority_queue , less>
23#define pqs priority_queue , greater>
24#define vec vector
25 ld eps=1e-9
;26 ll pp=1000000007
;27 ll mo(ll a,ll pp)
28 ll powmod(ll a,ll b,ll pp)
29void fre()
30//
void add(int x,int y,int z)
31int dx[5]=,dy[5]=;
32 ll read()
37int n,a[101],f[101][2001
],h;
38int
main()
3956
if (f[n][0]<=0
)57 printf("
%s","
impossible");
58else
59 printf("
%d\n
",f[n][0
]);60 }
終於這道題完美的解決了。
搭建雙塔(Vijos 1037)
2001年9月11日,一場突發的災難將紐約世界 中心大廈夷為平地,mr.f曾親眼目睹了這次災難。為了紀念 9?11 事件,mr.f決定自己用水晶來搭建一座雙塔。mr.f有n塊水晶,每塊水晶有乙個高度,他想用這n塊水晶搭建兩座有同樣高度的塔,使他們成為一座雙塔,mr.f可以從這n塊水晶中任取m 1 m...
vijos1037 搭建雙塔
題目 限制和答案,到底哪乙個應該是陣列下標 設f i j 為取到第i個水晶,高度差為j時的較高塔的最高高度 那答案的更新,分方和不放討論 一 不放,dp i j dp i 1 j 二 放 放的話,對答案影響有三種情況 1 放在較高塔上,dp i j dp i j h i h i 高度差增加h i 高...
搭建雙塔(vijos 1037)
2001年9月11日,一場突發的災難將紐約世界 中心大廈夷為平地,mr.f曾親眼目睹了這次災難。為了紀念 9?11 事件,mr.f決定自己用水晶來搭建一座雙塔。mr.f有n塊水晶,每塊水晶有乙個高度,他想用這n塊水晶搭建兩座有同樣高度的塔,使他們成為一座雙塔,mr.f可以從這n塊水晶中任取m 1 m...