給你乙個n*n的格仔的棋盤,每個格仔裡面有乙個非負數。
從中取出若干個數,使得任意的兩個數所在的格仔沒有公共邊,就是說所取的數所在的2個格仔不能相鄰,並且取出的數的和最大。
包括多個測試例項,每個測試例項包括乙個整數n
nn和n×n
n\times n
n×n個非負數(n≤20
n\leq 20
n≤20
)對於每個測試例項,輸出可能取得的最大的和
3
75 15 21
75 15 28
34 70 5
188
我們可以自上而下、一行行地選擇格仔。在一行內選擇格仔的時候,只和上一行的選擇方案有關,我們就可以將」 當前放到第幾行、當前行的選擇方案」作為狀態進行動態規劃。
這裡,我們就要用到狀態壓縮: 一行裡被選擇的格仔實際上是乙個集合, 我們要將這個集合壓縮為乙個整數。比如,對於乙個3
33列的矩陣,如果當前行的狀態是(5)
10=
(101)2
(5)_ = (101)_2
(5)10
=(10
1)2
,那麼就意味著當前行選擇了第一 個和第三個格仔;類似地,如果當前行的狀態是(6)
10=
(110)2
(6)_ = (110)_2
(6)10
=(11
0)2
,那麼就意味著當前行選擇了第-個和第二個格仔 (當然由於計算順序的緣故,我們通常會把(
110)
2(110)_2
(110)2
當做選擇倒數第乙個和倒數第二 個格仔, 這並不影響我們理解這道題的解法)。
如果上一行的狀態是now
, 下一行的狀態是prev
, 那麼我們只需要確保上下兩行的選擇方案裡沒有重複的元素,也就是(now & prev)==0
就可以了。
此外,我們還需要判斷當前行的狀態是否合法,因為讀入的矩陣中並不是每個格仔都可以選擇的,如果我們將矩陣中每行的值也用狀態壓縮來儲存,不妨記為flag,那麼當前行選擇的格仔集合一定包含於當前行合法格仔的集合,也就是說,(now | flag) == flag
必須成立;同時行內也不能選擇相鄰的,也就是now & (now >> 1) ==0
必須成立。
這樣,我們就可以通過列舉上一 行的所有狀態,來更新當前行、當前狀態的最優解了。直到算完最後一行,統計一下所有狀態的最大值即可。
**:
#include
#include
using
namespace std;
int a[21]
[20];
int state[21]
;//初始每行的狀態
int dp[21]
[1<<20]
;boolok(
int now)
bool
fit(
int now,
int i)
bool
not_intersect
(int now,
int prev)
intcount
(int now)
return s;
}int
main()
}for
(int i=
1;i<=n;i++)}
}for
(int i=
1;i<=n;i++)}
}}}int ans=0;
for(
int i=
0;i<(1
<;i++
)printf
("%d"
,ans)
;return0;
}
題解 方格取數問題
傳送門 在乙個有 m n 個方格的棋盤中,每個方格中有乙個正整數。現要從方格中取數,使任意 2 個數所在方格沒有公共邊,且取出的數的總和最大。試設計乙個滿足要求的取數演算法。對於給定的方格棋盤,按照取數要求程式設計找出總和最大的數。這個題目也是很明顯的網路流,奇偶性建圖,最後總和 最小割即為答案 i...
題解 方格取數問題
題目戳我 text 相鄰的不能取 黑白染色。染色完之後,我們需要對不能同時選擇的點連線一條流量為 infty 的邊,以保證它們不被割開。即,被割開的一定是連向 s 或 t 的之前連過的邊,邊權是點權。上述連邊保證圖聯通,並保證割掉的邊一定是之前連的邊權為點權的邊。如果不連 infty 的邊,則原圖本...
題解 方格取數問題 網路流
考慮這個要求 沒有共同邊 像極了最小割。最小割 將圖依照 s 和 t 分為兩個互無交集的集合,並且使得刪去的元素 邊 的權值和最小。然後我們看看這個問題,先要分類以確定和 s 在一起和和 t 在一起的點。顯然由於相鄰點是對立的所以我們直接相鄰的連 inf 邊表示這個相鄰關係無法被改變。這樣這條邊在最...