b——區間選點(貪心)
c——區間覆蓋問題(貪心)
給出n個正數,從其中選出k個數,使其總和為s,問:有多少種選數方案?
input
第一行是正數t(t<=100),表示測試的組數。每一組都輸入兩行,第一行是三個整數n,k,s,第二行是n個正整數。
output
每一組輸出結果佔一行,為方案的數目。
sample input
1
10 3 10
1 2 3 4 5 6 7 8 9 10
sample output
4
dfs,每組將輸入的n個數存在a陣列中,選擇的數存放在pick陣列中,利用solve函式,從a中第0位起,將下一位分兩種情況:不加入已選陣列,加入的已選陣列中,再進入下一位的solve函式中,進行遞迴,直到第n位。其中進行了可行性剪枝,對已選數多於k個以及已選數的和大於s的情況進行返回。當選擇的k個數總和為s時,方案數增加,及時返回。
可行性剪枝可以省下部分遞迴操作,節省了時間。還要注意每組操作之前需要清空a陣列,以及對方案數目重置0。
#
include
#include
#include
using
namespace std;
int t,count,n,k,s,m;
list<
int> pick;
vector<
int> a;
void
solve
(int i,
int sum,list<
int>
&pick)
if(i>=n || pick.
size()
>k ||sum<0)
return
;//超過選數邊界n 或 已選數多於k個 或 已選數和大於sum,則返回
solve
(i+1
,sum,pick)
;//不選第i+1個數
pick.
push_back
(a[i]);
//將第i+1個數加入已選數中
solve
(i+1
,sum-a[i]
,pick)
;//選第i+1個數
pick.
pop_back()
;}intmain()
solve(0
,s,pick)
; cout<}return0;
}
數軸上有 n 個閉區間 [a_i, b_i]。取盡量少的點,使得每個區間內都至少有乙個點(不同區間內含的點可以是同乙個)
input
第一行1個整數n(n<=100)
第2~n+1行,每行兩個整數a,b(a,b<=100)
output
乙個整數,代表選點的數目
sample input1
2
1 54 6
sample output1
1
sample input2
3
1 32 5
4 6
sample output2
2
貪心,要想盡量選取少的點使每個區間都至少乙個點,這個點一定處在這個區間與盡可能多的其他區間交叉重合的段。
將所有區間用結構體line陣列儲存,包含左端點和右端點的值。定義cmp排序標準,將所有區間的右端點按照從小到大排序,若右端點相同,則按左端點從大到小排序(盡快找到與之前區間未交叉重合的區間:小區間被交叉的話,包含他的大區間也必然被交叉,小區間應該優先排列),排序所有區間。接下來,只要選擇區間的右端點即可。
先將第乙個區間的右端點設為用於對比的邊界p,第乙個邊界先有乙個點標記,區間陣列的區間依次看,如果左端點比p大,則表示該區間與前面的區間是分離的、未交叉,需要用乙個新的點標記,p也需要更新到該區間的右端點。這樣一直到所有區間都對比完。
#
include
#include
using
namespace std;
int pointnum=0;
int n,a,b;
struct
line
;bool
compare
(line &x,line &y)
intmain()
sort
(l,l+n,compare)
;int p=l[0]
.right;
//開始的右邊界選第乙個區間的右端點
pointnum++
;//一開始用乙個點標記第乙個區間
for(
int j=
1;jcout
}
數軸上有 n (1<=n<=25000)個閉區間 [ai, bi],選擇盡量少的區間覆蓋一條指定線段 [1, t]( 1<=t<=1,000,000)。
覆蓋整點,即(1,2)+(3,4)可以覆蓋(1,4)。
不可能辦到輸出-1
input
第一行:n和t
第二行至n+1行: 每一行乙個閉區間。
output
選擇的區間的數目,不可能辦到輸出-1
sample input
3 10
1 73 6
6 10
sample output
2
貪心,要選中盡量少的區間覆蓋1~t這段線段,就要選擇能夠連續接壤且範圍最廣的區間。
仍然是把區間儲存在line結構體中,有左、右端點值。對所有區間按照左端點由小到大排序。設定乙個標誌flag(初始為true,記錄是否能連續接壤,不能置為false),乙個cur變數(記錄每一次用來對比的起點,初始為1),end變數(記錄上乙個被選擇的區間的右端點,初始為0)。
在end未到達線段終點t時,一直重複乙個工作,尋找與起點cur接壤的最大區間,從第乙個區間起開始遍歷,若接壤且未被包含,則選擇該區間,其右端點作為end的新值,直到區間都被比較完,則最後的end值就是接壤且範圍最大的區間。區間被比較完後,判斷是否選擇了新的區間作為end,如果沒有選擇新的,則說明無法連續覆蓋該線段,直接退出迴圈輸出-1,將標誌設為false。若選擇了新的區間,則區間選擇數增加,將cur設定在end的右乙個位置,作為新起點。
這道題很容易因為線段是否被完整覆蓋的錯誤判斷而wa,將起點cur設定成end+1,更好的進行比較判斷,不用對區間端點是否重合再進行多情況討論。
#
include
#include
#include
using
namespace std;
struct
line};
bool
cmp(line &x,line &y)
intmain()
sort
(vl.
begin()
,vl.
end(
),cmp)
; num=0;
len=0;
int cur=1;
//每一次劃分的起點,初始為1
int end=0;
//上一段區間的右端點,初始為0
j=0;while
(end//線段被完整覆蓋時退出迴圈}if
(cur>end)
//若未找到連續覆蓋線段的區間,則說明斷開連線
num++
; cur=end+1;
//}if(flag)//能夠完整覆蓋線段時輸出區間個數
cout
}
程式設計思維與實踐 Week3 作業
給定n個正數,從中選出k個數,令其和為s,求選數的方案數。對於每乙個數選擇與不選擇都進行dfs 邊界條件 選中k個數且和為s 選中數的個數大於k 選中數的和大於s 要選的數越界了 include using namespace std int ans 0 int a 2000 int n,k,s v...
程式設計思維與實踐 week3
題目 題意 給定n個正整數,要求選出k個數,使選出來的k個數和為sum,共有多少個方案?輸入 第一行乙個數t t 100 表示有t組測試資料。接下來的兩行,一行有三個數n,k,s,一行有n個正整數。輸出 每組資料輸出乙個和為s的方案個數,每組佔一行。思路 dfs 可行性剪枝 子集列舉問題。列舉所有子...
程式設計思維與實踐 Week3 作業 B區間選點
題意 數軸上有n個閉區間,在數軸上選取盡量少的點,使得每個區間上都有乙個點,其中乙個點可以覆蓋多個區間。思路 將各個點用結構體記錄下來,分別記錄下左右邊界。不妨設左端點為a,右端點為b。對這些點進行排序,然後將區間按b 從小到大排序 b 相同時a 從大到小排序 然後從前往後進行選點,點為選擇前乙個區...