codeforces511div1_b Little C Loves 3 II (二分圖匹配+打表+找規律)
阿新 • • 發佈:2018-11-01
題意
給出 n和m並且 的矩陣,每次往裡面放兩個棋子,這兩個棋子要滿足曼哈頓距離等於3,問最多可以放多少枚棋子。
題解
你會發現手畫是根本搞不出來的,想靠手畫找規律可能需要有成為錦鯉的運氣。每個點都可能會與周圍距離為3的點配對,從而放下棋子,但當你在另一個位置放棋子時,若其周圍距離為3的點與之前放棋子的點衝突,那該如何解決? 這個問題便是二分圖最大匹配問題,我們把方格看成點構成一張圖跑二分圖匹配即可。但是! 若n,m小於100還好說,此題的n,m是爆炸級別的,根本沒法跑複雜度平方級別的演算法,那就用剛剛寫的程式打表找找規律吧。 這裡又有一個很神奇的地方,當n和m為奇數的時候,輸出
,當其中一個為偶數的時候,輸出
,但是!當n和m小於20的時候,這種情況就不在符合。所以對n和m小於20的情況,跑二分圖匹配,其餘的按照規律輸出即可。(奇技淫巧啊)
補充: 對與
的情況要特殊處理下,明顯1x6的矩陣可以擺滿棋子,所以答案為
。
程式碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000;
const int dr[] = {3,2,1,0,-3,-2,-1,0, 2, 1, 0,-3,-2,-1};
const int dc[] = {0,1,2,3, 0, 1, 2,3,-1,-2,-3,0,-1,-2};
const int MAXN = 2000;
const int INF = 0x3f3f3f3f;
long long n,m;
int cnt;
int g[maxn][maxn];
typedef pair<int,int> pii;
map<pii,int> id;
int ID(pii p) {
if(id.count(p)) return id[p];
return id[p] = ++cnt;
}
int Nx,Ny;
void build() {
for(int i = 0; i < n; ++i)
for(int j = 0; j < m; ++j) {
for(int k = 0; k < 14; ++k) {
int ni = i+dr[k], nj = j+dc[k];
if(ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
g[ID(pii(i,j))][ID(pii(ni,nj))] = 1;
Ny++;
}
}
}
bool flag;
int Mx[MAXN], My[MAXN];
int dx[MAXN], dy[MAXN], dis;
bool vst[MAXN];
bool searchP(void)
{
queue <int> Q;
dis = INF;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
for (int i = 1; i <= Nx; i++)
if (Mx[i] == -1){
Q.push(i); dx[i] = 0;
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (dx[u] > dis) break;
for (int v = 1; v <= Ny; v++)
if (g[u][v] && dy[v] == -1) {
dy[v] = dx[u]+1;
if (My[v] == -1) dis = dy[v];
else{
dx[My[v]] = dy[v]+1;
Q.push(My[v]);
}
}
}
return dis != INF;
}
bool DFS(int u){
for (int v = 1; v <= Ny; v++)
if (!vst[v] && g[u][v] && dy[v] == dx[u]+1) {
vst[v] = 1;
if (My[v] != -1 && dy[v] == dis) continue;
if (My[v] == -1 || DFS(My[v])) {
My[v] = u; Mx[u] = v;
return 1;
}
}
return 0;
}
int MaxMatch(void){
int res = 0;
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
while (searchP()) {
memset(vst, 0, sizeof(vst));
for (int i = 1; i <= Nx; i++)
if (Mx[i] == -1 && DFS(i)) res++;
}
return res;
}
void init() {
memset(g,0,sizeof g);
id.clear();
memset(vst, 0 ,sizeof vst);
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
cnt = 0;
}
/*
int main() {
while(cin >> n >> m){
init();
Nx = n*m;
Ny = 0;
build();
cout << MaxMatch() << endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
*/
int main() {
cin >> n >> m;
if(n > m) swap(n,m);
if(n == 1) {
cout << 6*(m/6)+2*max(m%6-3,1ll*0);
}
else if(n <= 20 && m <= 20) {
Nx = n*m;
Ny = 0;
build();
cout << MaxMatch() << endl;
}
else {
if(n%2 == 0 && m%2 == 0)
cout << n*m << endl;
else if(n%2 == 0 && m%2 || n%2 && m%2==0)
cout << n*m << endl;
else {
cout << n*m-1 << endl;
}
}
return 0;
}