力扣 223 場 周賽總結 並查集 狀態壓縮

2021-10-14 16:42:07 字數 3483 閱讀 5924

1722. 執行交換操作後的最小漢明距離

(相似題目:1202. 交換字串中的元素

1723. 完成所有工作的最短時間

首先兩題剛拿到的時候思路都是正確的——(3) 的尋找連通區域和遍歷 和(4) 的二分答案範圍來求解,總體難度感覺不高,但是還是沒有做出來。

對於(3): 對於並查集中的劃分連通區域不熟悉(利用map來處理)  (4) 對於狀態壓縮不熟悉(利用二進位制來遍歷求解揹包問題)

剛開始想複雜了,想著用map來儲存每乙個結點為頭的連通區域,這樣會使合併兩個結點的時候過於複雜,而可以就普通合併之後,再遍歷一次

兩種方法,但是第二種優於第一種(時間空間上都是)

並查集的合併連通區域的方法,設定乙個map來記錄每乙個節點所帶的子節點

map> mp;

// mp[i] = i 結點的子節點

void union_ab(int a,int b)

mp[a].clear();

}else

mp[b].clear();}}

// 使用rank可以優化查詢的時間複雜度

void union_ab(int a,int b)

}map[findfa(a)].push_back(a); // 在a的連通區域中增加結點

然後再遍歷一遍

parent[i] == i

// 表示 結點 i 為某乙個連通區域的頭結點,遍歷改區域即可

【狀壓dp】新手教學,拋棄繁瑣的 dfs 剪枝優化 

動態規劃——狀態壓縮dp 

狀態壓縮的主要的思想就是有乙個二進位制串來表示當前的狀態

比如 有5個揹包(a0,a1,a2,a3,a4)來表示是否為空,則 6(00110)就表示a2,a3的揹包不為空而其他揹包為空

總結一下,我們用二進位制的0和1表示乙個二元集合的狀態。

可以簡單認為某個物品存在或者不存在的狀態。

由於二進位制的0和1可以轉化成乙個int整數,也就是說我們用整數代表了乙個集合的狀態。

這樣一來,我們可以用整數的加減計算來代表集合狀態的變化

這是乙個np-hard問題。(具體簡紹在下面)

for (int sub = s; sub; sub = (sub - 1) & s)
class solution 

}int l = *max_element(jobs.begin(), jobs.end());

int r = accumulate(jobs.begin(), jobs.end(), 0);

// 確定上下邊界

while (r >= l) }}

// 當最小工作工人的數量小於已有的工人時 更新r

if (dp[(1

}vector> dp(k+1, vector(1 << n, -1));

// dp[i][j] -> 前 i 個工人為了完成作業子集 j,需要花費的最大工作時間的最小值。

/* 轉移方程 : dp[i][j] = 遍歷 s為j的子集 min(

max(dp[i-1][j-s],tot[s]);)*/

int res = 0;

for (int i = 0; i < (1 << n); i++)

// 即只有乙個人的時候每個人需要完成的最小時間就是該工作集的總和

for (int j = 2; j <= k; j++)

dp[j][i] = minv;

}res = min(res,dp[j][(1因為這題的資料集 n == 12 ,可以通過深搜 + 剪枝 來解決

注意剪枝的技巧 從小到大列舉工人的數量

加入測試變數 test 來標記搜尋執行的次數 可以看到直接列舉的話數量集是很高的,而從小到大列舉會縮小時間複雜度

並且還可以進行優化,在將jobs[a] 放入集合時,優先放入工作時間少的,這樣時間複雜度會進一步提高

// 深搜 將工作a列舉加入每乙個工人的集合

for(int i = 0;i& _jobs, int k)

};

p問題可以認為是已經解決的問題,這個解決的定義是可以做多項式的時間複雜度內解決。

所謂的多項式,也就是o(n^k),這裡的k是乙個常數。

與多項式相反的函式有很多,比如指數函式、階乘等等。

np問題並不是p問題的反義,這裡的n不能理解成no,就好像nosql不是非sql的意思一樣。np問題指的是可以在多項式內驗證解的問題

比如給定乙個排序的序列讓我們判斷它是不是有序的,這很簡單,我們只需要遍歷一下就好了。再比如大整數的因式分解,我們來做因式分解會很難,但是讓我們判斷乙個因式分解的解法是不是正確則要簡單得多,我們直接把它們乘起來和原式比較就可以了。

顯然所有p問題都是np問題,既然我們可以多項式內找到解,那麼必然我們也可以在多項式內驗證解是否正確。但是反過來是否成立呢,是否多項式時間內可以驗證解的問題,也可以通過某種演算法可以在多項式時間內被解開呢?究竟是我們暫時還沒有想到演算法,還是解法一開始就不存在呢?

為了證明這個問題,科學家們又想出了乙個辦法,就是給問題做規約。舉個例子,比如解方程,我們解一元一次方程非常簡單,而解二元一次方程則要困難一些。如果我們想出了解二元一次方程的辦法,那麼必然也可以用來解一元一次方程,因為我們只需要令另乙個未知數等於0就是一元一次方程了。

同理,我們也可以把np問題做轉化,將它的難度增大,增大到極限成為乙個終極問題。由於這個終極問題是所有np問題轉化得到的,只要我們想出演算法來解決了終極問題,那麼,所有的np問題全部都迎刃而解。就比如如果我們想出了解n元方程的演算法,那麼這一類解方程的問題就都搞定了。這種轉化之後得到的問題稱為np完全問題,也叫做npc問題

最後,還有乙個np-hard問題,np-hard問題是說所有np問題可以經過轉化得到它,但是它本身並不是np問題,也就是說我們無法在多項式時間內判斷它的解是否正確。

力扣第 260 場周賽總結

周賽入口 位元組跳動 力扣 聯合主辦 第 260 場周賽 給你乙個下標從 0 開始的整數陣列 nums 該陣列的大小為 n 請你計算 nums j nums i 能求得的 最大差值 其中 0 i j n 且 nums i nums j 返回 最大差值 如果不存在滿足要求的 i 和 j 返回 1 示例...

力扣第165場周賽

a 和 b 在乙個 3 x 3 的網格上玩井字棋。井字棋遊戲的規則如下 玩家輪流將棋子放在空方格 上。第乙個玩家 a 總是用 x 作為棋子,而第二個玩家 b 總是用 o 作為棋子。x 和 o 只能放在空方格中,而不能放在已經被占用的方格上。只要有 3 個相同的 非空 棋子排成一條直線 行 列 對角線...

力扣第 202 場周賽

傳送門 5185 存在連續三個奇數的陣列 給你乙個整數陣列 arr,請你判斷陣列中是否存在連續三個元素都是奇數的情況 如果存在,請返回 true 否則,返回 false 示例 1 輸入 arr 2,6,4,1 輸出 false 解釋 不存在連續三個元素都是奇數的情況。示例 2 輸入 arr 1,2,...