1. 程式人生 > >codeforces511div1_b Little C Loves 3 II (二分圖匹配+打表+找規律)

codeforces511div1_b Little C Loves 3 II (二分圖匹配+打表+找規律)

題意

給出 n和m並且 1 < n , m < 1 e 9

1< n,m < 1e9 的矩陣,每次往裡面放兩個棋子,這兩個棋子要滿足曼哈頓距離等於3,問最多可以放多少枚棋子。

題解

你會發現手畫是根本搞不出來的,想靠手畫找規律可能需要有成為錦鯉的運氣。每個點都可能會與周圍距離為3的點配對,從而放下棋子,但當你在另一個位置放棋子時,若其周圍距離為3的點與之前放棋子的點衝突,那該如何解決? 這個問題便是二分圖最大匹配問題,我們把方格看成點構成一張圖跑二分圖匹配即可。但是! 若n,m小於100還好說,此題的n,m是爆炸級別的,根本沒法跑複雜度平方級別的演算法,那就用剛剛寫的程式打表找找規律吧。 這裡又有一個很神奇的地方,當n和m為奇數的時候,輸出 n

m 1 n*m-1 ,當其中一個為偶數的時候,輸出 n m
n*m
,但是!當n和m小於20的時候,這種情況就不在符合。所以對n和m小於20的情況,跑二分圖匹配,其餘的按照規律輸出即可。(奇技淫巧啊)
補充: 對與 n = 1 m = 1 n=1或者m=1 的情況要特殊處理下,明顯1x6的矩陣可以擺滿棋子,所以答案為 6 m 6 + 2 m a x { ( m   m o d   6 ) 3 , 0 } 6*\lfloor\frac{m}{6}\rfloor+2*max\{ (m\ mod\ 6 )- 3, 0\}

程式碼



#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;
}