給出n
nn根欄杆的長度,讓你從這n
nn根欄杆中選出一些欄杆圍成乙個矩形(必須要剛好圍成乙個矩形,即不能出現多餘的邊長,且不能切斷欄杆,但所給欄杆不一定要全部用上),求圍成矩形的最大面積。
對於30
%30\%
30%的資料,1≤n
≤10
1 \leq n \leq 10
1≤n≤10
;對於100
%100\%
100%
的資料,1≤n
≤16
1 \leq n \leq 16
1≤n≤16
,1
≤欄杆的長度≤15
1 \leq \text \leq 15
1≤欄杆的長度≤1
5。這是一道狀態壓縮動態規劃(狀壓dpdp
dp)題。30分
對於30
%30\%
30%的資料,我們可以用暴力求出。設圍成的矩形的四條邊分別為e1,
e2,e
3,e4
e_1,e_2,e_3,e_4
e1,e2
,e3
,e4
,那麼在dfs
dfsdf
s時列舉每條邊的每種情況(加入e
1e_1
e1或e
2e_2
e2或e
3e_3
e3或e
4e_4
e4),最後判斷矩形的長寬是否相等,如果相等就更新答案。**如下:
#
include
intmax
(int x,
int y)
//最大值函式
return y;
}int n,a[22]
;int
dfs(
int s/*列舉的欄杆的編號*/
,int e1/*矩形的第一條長*/
,int e2/*矩形的第二條長*/
,int e3/*矩形的第一條寬*/
,int e4/*矩形的第二條寬*/
)return0;
}return
max(
max(
max(
dfs(s+
1,e1+a[s]
,e2,e3,e4)
,//加入e1
dfs(s+
1,e1,e2+a[s]
,e3,e4)),
//加入e2
max(
dfs(s+
1,e1,e2,e3+a[s]
,e4)
,//加入e3
dfs(s+
1,e1,e2,e3,e4+a[s]))
),//加入e4
dfs(s+
1,e1,e2,e3,e4));
//不選
}int
main()
int t=
dfs(1,
0,0,
0,0)
;//dfs
if(t==0)
//如果無解
else
return0;
}
這樣的時間複雜度為o(5
n)
o(5^n)
o(5n
),100
%100\%
100%
的資料肯定過不了,於是我們考慮對其優化。
100分
因為我們知道矩形的長、寬相等,所以我們設它的長為a
aa,寬為b
bb,深蒐時每根欄杆的情況就由5
55種降到了3
33種:加入a
aa,加入b
bb,不選。最後我們再判斷a
aa,b
bb是否可以分成相等的兩部分,如果可以更新答案即可。
如何判斷a
aa,b
bb是否可以分成相等的兩部分呢?我們用f
ff陣列來判斷。f
if_i
fi(i
ii為乙個01
0101
串)表示對於i
ii這種選擇欄杆的情況中,選出的欄杆能否分成相等的兩段。因為i
ii是乙個01
0101
串,所以我們可以把它壓縮成乙個十進位制數儲存。
對於每個i
ii,我們先求出選出的欄杆的長度總和sum
sumsu
m。如果sum
sumsu
m是奇數,那麼顯然fi=
fals
ef_i=false
fi=fa
lse。否則我們用01
0101
不帶權揹包g
gg輔助處理。我們把選出的欄杆逐個放入g
gg中,然後判斷gsu
m÷2g_
gsum÷2
(一半)能否被組合,若能,表示sum
−sum
÷2
sum-sum \div 2
sum−su
m÷2(即另一半)也能被組合,fi=
true
f_i=true
fi=tr
ue;否則,fi=
fals
ef_i=false
fi=fa
lse。
根據以上思路,我們可以打出如下**:
#
include
bool f[
1<<16]
,g[242];
int n,l[22]
;int
max(
int x,
int y)
//最大值函式
return y;
}int
dfs(
int s/*列舉的欄杆的編號*/
,int a/*長的選擇情況*/
,int suma/*兩條長的總和*/
,int b/*寬的選擇情況*/
,int sumb/*兩條寬的總和*/
)return0;
}return
max(
max(
dfs(s+
1,a+(1
<<
(s-1))
,suma+l[s]
,b,sumb)
/*加入長*/
,dfs
(s+1
,a,suma,b+(1
<<
(s-1))
,sumb+l[s]))
/*加入寬*/
,dfs
(s+1
,a,suma,b,sumb)
/*不選*/);
}int
main()
int m=
1
int i=
0;i)//列舉每種情況}if
(sum%2!=
0)//如果長度除以2不是整數(無法平均分成相等的兩個整數部分)
else
for(
int j=
1;j<=n;j++
)//列舉每一條邊}}
f[i]
=g[sum/2]
;//判斷能否被分成相等的兩部分}}
int t=
dfs(1,
0,0,
0,0)
;//dfs
if(t==0)
//如果無解
else
return0;
}
在做像這樣的狀壓dpdp
dp題時,可以先打出暴力,然後再嘗試對其優化。
DP專題 2679 跨時代
1.題目描述 鐘逆時針而繞,噁物猙獰的傾巢,我謙卑安靜地於城堡下的晚禱,壓抑遠古流竄的蠻荒暗號,而管風琴鍵高傲的說,那只是在徒勞。我的樂器在環繞,時代無法淘汰我霸氣的皇朝。你無法預言,因為我越險,翅越豔 沒有句點,跨時代蔓延,翼朝天。月下浮雕,魔鬼的淺笑,狼迎風嚎,蝠翔似黑潮,用孤獨去調尊嚴的色調。...
JZOJ 2679 跨時代 dfs 狀壓
傳送門 有n nn個棍子,要求我們用這些棍子可以拼出的矩形的最大面積 棍子可以不全用 因為n nn很小,又涉及到方案,我們便開始嘗試用狀壓來表示方案 用d fs dfsdf s來列舉棍子是否使用,憑藉前面狀壓表示出來的方案判斷是否可行,不斷取最大值 include include include i...
jzoj2679 跨時代 揹包,dfs,狀壓
若干根棍子,不能折,不能多餘求能夠組成的最大長方形。首先我們發現如果棍子集合s ss長度為l ll且它有子集g gg長度為l 2 frac 2l 那麼就表示這個集合的棍子可以作為乙個矩形的對應兩邊,這樣我們只要列舉兩個不相交集合作為長寬就好了。我們設g ig i gi 表示二進位制表示的集合i ii...