程式設計思維與實踐 week3

2021-10-04 02:40:38 字數 4034 閱讀 9413

題目:

題意:給定n個正整數,要求選出k個數,使選出來的k個數和為sum,共有多少個方案?

輸入:第一行乙個數t(t<=100),表示有t組測試資料。接下來的兩行,一行有三個數n,k,s,一行有n個正整數。

輸出:每組資料輸出乙個和為s的方案個數,每組佔一行。

思路:dfs/可行性剪枝

子集列舉問題。列舉所有子集是否合法。

但是列舉全部子集複雜度過高,所以需要優化。

由於合法的方案個數一定不多,而列舉的子集數量較大,所以可行性剪枝可以有效地優化時間。

對於每乙個子集,若選的數的個數超過了k,或者選的數的和超過了s,可以直接捨去。

總結:有多組測試資料時,請一定一定要注意清空的問題!

由於dfs是在所有的可能情況裡找可行解,這棵搜尋樹相當大,所以適當的可行性剪枝/最優性剪枝可以很好地減少搜尋,在可能的範圍很大但是解相對很少的情況下,要考慮剪枝。

**:

#include

#include

using

namespace std;

int t;

int n,k,s;

int count;

vector<

int> a;

//子集排列

void

subset

(vector<

int>

& num,

int m,

int sum)

//1-n存子集

if(num.

size()

>k||sum>s)

return;

num.

push_back

(a[m-1]

);//選

sum=sum+a[m-1]

;subset

(num,m+

1,sum);

num.

pop_back()

;//不選

sum=sum-a[m-1]

;subset

(num,m+

1,sum);}

intmain()

vector<

int> num;

subset

(num,1,

0); cout

clear()

;//要清空,不然就一直在插入

}return0;

}

題目:

題意:數軸上有 n 個閉區間 [ai, bi]。取盡量少的點,使得每個區間內都至少有乙個點(不同區間內含的點可以是同乙個)

輸入:第一行1個整數n(n<=100);第2~n+1行,每行兩個整數a,b(a,b<=100)

輸出:乙個整數,代表選點的數目

思路:貪心

希望每次選的數可以包括最多的區間,所以每次取的數都是所有被包括的區間的最大的bi。而為了使所有的區間都被包括,所以第乙個取的數一定是bi最小的那個區間的bi。

對於每乙個區間[ai, bi],將所有區間按bi公升序排列。

用乙個變數theend記錄已經判斷過的所有區間的最大的bi,對於剩下的為判斷過的區間,將其起點ai與theend比較,若ai

<=theend,這說明該區間可以被目前的bi包括;若ai>theend,這說明該區間不能被包括,則需要增加選的數,並將theend設為這個區間的bi。

總結:現在再看自己的**,貌似while迴圈和for迴圈有冗餘ヽ(´ー`)┌這個num變數並沒什麼用,遍歷完一遍就行了。

**:

#include

#include

using

namespace std;

int n;

int a,b;

struct section};

section s[

100]

;int

main()

//sort

sort

(s,s+n)

;//貪心

int num=1;

//已被包括的區間個數

int count=1;

int theend=s[0]

.end;

s[0].flag=1;

//被包括

bool up=0;

while

(numif(s[i]

.flag==

0&&s[i]

.begin>theend)}}

//output

cout

}

題目:

題意:數軸上有 n (1<=n<=25000)個閉區間 [ai, bi],選擇盡量少的區間覆蓋一條指定線段 [1, t]( 1<=t<=1,000,000)。

覆蓋整點,即(1,2)+(3,4)可以覆蓋(1,4)。

不可能辦到輸出-1

輸入:第一行:n和t;第二行至n+1行: 每一行乙個閉區間。

輸出:選擇的區間的數目,不可能辦到輸出-1。

思路:貪心

由於題目要求的是覆蓋整點,所以先對所有的區間的頭尾取整,頭向上取整,尾向下取整(然而我懷疑這道題的資料不需要取整,大概全是整數 。

為了覆蓋指定線段,應該從左向右考慮,先考慮包括了整點1的區間最長能覆蓋到哪個整點(設這個整點為wi),再考慮包括了wi+1的整點的區間最長能覆蓋到哪個整點wi+1,一直到覆蓋整點t。

所以對所有的區間排序,以起點為第一關鍵字公升序排序,以終點為第二關鍵字公升序排序。

然後從第乙個區間開始,若第乙個區間的左端點大於1,則不能覆蓋指定線段,輸出-1。反之,記覆蓋的最遠的整點為tail,對後面所有未被判斷過的區間[ai, bi]進行tail的判斷(注意這裡的ai, bi指的是取整後的端點)。

我要尋找的是ai

<=tail+1且bi>tail的區間裡bi最大的那個區間,由於已經對所有區間進行排序,所以只要判斷上述條件直到最後乙個成立的區間就是我所要找的區間。

最後拿tail與t判斷即可。

總結:貪心準則還是很容易找錯的,但仔細想的時候會發現貪心準則和平時我們想的思路很像,所以如果一步一步地細化思路的話,還是可以找到比較正確的貪心準則的。

感覺貪心的證明好難 (〒︿〒) 多多積累經驗叭

**:

#include

#include

#include

using

namespace std;

int n;

double t,a,b;

struct section};

section s[

25000];

intmain()

//sort

sort

(s,s+n)

;//judge

double head=s[0]

.begin;

double tail=s[0]

.end;

//s[0].flag=1;

int count=1;

//選中區間的數量

bool ff=0;

if(head<1)

printf

("-1");

//不可能

else

else

if(s[i]

.begin<=tail+

1&&s[i]

.end>tail+

1&&s[i]

.flag==0)

//tail需要更新了

} s[i]

.flag=1;

tail=tmp;

count++;}

if(head<=

1&&tail>=

floor

(t))

ff=1;

//成功 }if

(i==n&&ff==0)

printf

("-1");

//未成功

else

printf

("%d"

,count);}

return0;

}

程式設計思維與實踐 Week3 作業

b 區間選點 貪心 c 區間覆蓋問題 貪心 給出n個正數,從其中選出k個數,使其總和為s,問 有多少種選數方案?input 第一行是正數t t 100 表示測試的組數。每一組都輸入兩行,第一行是三個整數n,k,s,第二行是n個正整數。output 每一組輸出結果佔一行,為方案的數目。sample i...

程式設計思維與實踐 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 作業 B區間選點

題意 數軸上有n個閉區間,在數軸上選取盡量少的點,使得每個區間上都有乙個點,其中乙個點可以覆蓋多個區間。思路 將各個點用結構體記錄下來,分別記錄下左右邊界。不妨設左端點為a,右端點為b。對這些點進行排序,然後將區間按b 從小到大排序 b 相同時a 從大到小排序 然後從前往後進行選點,點為選擇前乙個區...