方格取數問題
題目描述
在乙個有m*n個方格的棋盤中,每個方格中有乙個正整數。現要從方格中取數,使任意2個數所在方格沒有公共邊,且取出的數的總和最大。試設計乙個滿足要求的取數演算法。
輸入格式
檔案第1行有2個正整數m和n,分別表示棋盤的行數和列數。接下來的m行,每行有n個正整數,表示棋盤方格中的數。(0 <= m, n <= 30)
輸出格式
取數的最大總和.
輸入樣例
33 1 2 3
3 2 3
2 3 1
輸出樣例
11題目大意:
給出m*n的格仔,相鄰的格仔的值不可同時取,最後求出最大值。
我還誤以為只有兩種情況,用暴力不就好了嗎,不過wyy給我舉出其他情況,事實證明我想少了。
構圖:
如圖,我們會發現,黑色格仔都是可以同時選的,白色格仔也是同時可以走的。會發現同是黑色格仔(白色格仔),它們的行列座標加起來mod 2,都是一樣的。
所以,我們可以用二分圖來給它們歸類。首先,行列之和,為偶數的放在左邊,行列之和為奇數的放在右邊。於是,便得出,黑色格仔的放在右邊,白色格仔放在左邊。
因為黑白之間是互不可取的,以中間的黑色格仔為例,它不可達的格仔有它上下左右的白色格仔,於是把它們相連。同理,所有黑色格仔都這麼連。
並把黑色格仔(行列和為偶數)與s節點相連,白色格仔與t相連。
解題思想:
求出來的為最小割,也就是說,如果經過這個點,那就是把這個點割去了,不能選。而得出最小割,也就是得出了不選哪些格仔,所以,用總和減去最小割就是最後的答案。
細節:
我們一開始一直wrong,是因為陣列開小了,maxn直接開為35,可是在這乙個棋盤裡面,格仔數是遠遠不止這麼多的,要開到n^2。
**如下:
#include#include#includeusing namespace std;const int maxn=1000,oo=10000000;//注意陣列大小,格仔數為n^2。
int ans;
int cur=-1,s,t,m,n;
int head[maxn],c[maxn][maxn],v[maxn],id[maxn][maxn],a[maxn][maxn];
int xx[5]=,yy[5]=;
struct space
edge[maxn*maxn];
void add(int from,int to,int va,int type)
void build(int x,int y)
}void init()
} s=0,t=n*m+1;
for(int i=1;i<=m;i++) }
for(int i=1;i<=m;i++)
else
} } }
int dfs(int now,int mi)
} h=edge[h].next;
} return 0;
}//最小割(與最大流的**完全是一樣的)
int main()
cout<
這篇部落格寫得比較清楚。
網路流24題 方格取數
先對棋盤黑白染色 這是常見套路 我們發現,如果選了乙個黑點,那相鄰的白點就不能選,反之同理 出現了衝突關係,考慮最大權閉合子圖 把黑點看成正權點,白點看成負權點,黑點向相鄰白點連邊,跑最大權閉合子圖即可 include include include include define maxc 205 ...
網路流24題 方格取數
p2774 傳送門 方格取數和最大且要求兩兩沒有公共邊 遇到方格內的不相鄰問題,考慮黑白染色來對點分類 問題轉化為使黑點不和白點相鄰的最小代價,其中每個點的代價只計算一次 明顯的集合劃分模型,用最小割解決 include using namespace std define x first defi...
24題 方格取數問題 網路流
在乙個有 n m n times m n m 個方格的棋盤中,每個方格中有乙個正整數。現要從方格中取數,使任意 2 個數所在方格沒有公共邊,且取出的數的總和最大。這道題明顯是乙個二分圖。我們可以把每個點染色,將i j i ji j為偶數的點連向t tt,否則連向s ss。那麼對於每乙個連s ss的白...