二分图独立集
定理: 二分图最大独立集=n - 二分图最大匹配
其实二分图独立集是特殊的一种最大权闭合子图。我们根据上文“收益”的思想,把选某个点的收益看为1,左部节点为正权点,右部节点为负权点.按照最大权闭合子图的方式建图,答案为正权和-最小割=n-最小割=n-最大流。我们发现把最大权闭合子图中INF的边换成1也不影响答案,因为图中其他边的容量都为1。这样图就变成了二分图匹配中的图,最大流=二分图最大匹配
题目大意:
现在就是每个方格里面都有一个数值,但是你选了一个方格之后,它上下左右的都不能选了问你现在取出的数最大的和是多少?
解题思路:
-
现在就是我们要求和最大,那么就是冲突的数字要最小,那么我们把冲突这种关系表现为图的联通性的时候那么我们就可以用最小割去求解,就是假如这有两个数是冲突了,在图中就是他们同时存在的时候图是联通的!!
-
那么我们观察一下点就是上下左右的点:我们对棋盘进行黑白染色((横坐标+纵坐标)%2==1的点设为黑点),可以发现,若取一个黑格的点,受到影响的就是周围的白点。
-
然后可以发现这是一个最小割的套路题,假设所有的点都取,然后去掉最小割,就是答案了。
建模:S->黑点,容量为点权
白点->T,容量为点权
每一个黑点->取该黑点会受到影响的白点,容量为inf
然后就可以了
代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct node {
int to, next, len;
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
e[cnt] = {to,head[from],len};
head[from] = cnt ++;
}
int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];
bool bfs() {
ms(d,0);
queue<int> q;
q.push(s); d[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[v] || e[i].len <= 0) continue;
q.push(v);
d[v] = d[u] + 1;
}
}
for(int i = 0; i <= n; ++ i) cur[i] = head[i];
return d[t] != 0;
}
int dfs(int u, int flow) {
if(u == t) return flow;
for(int &i = cur[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
int delta = dfs(v,min(flow,e[i].len));
if(delta <= 0) continue;
e[i].len -= delta;
e[i^1].len += delta;
return delta;
}
return 0;
}
int get_maxflow() {
int maxFlow = 0, delta;
while(bfs())//bfs进行构建最短路网络
while(delta = dfs(s,INF))
maxFlow += delta;
return maxFlow;
}
int Tn, Tm;
int nx[] = {-1,0,1,0};
int ny[] = {0,1,0,-1};
int sum = 0;
int main() {
IOS;
ms(head,-1);
cin >> Tm >> Tn;
s = 0, t = Tm * Tn + 1;
n = t;
for(int i = 1; i <= Tm; ++ i) {
for(int j = 1; j <= Tn; ++ j) {
int x;
cin >> x;
sum += x;
if((i + j) & 1) add(s,(i-1)*Tn+j,x), add((i-1)*Tn+j,s,0);
else add((i-1)*Tn+j,t,x), add(t,(i-1)*Tn+j,0);
}
}
for(int i = 1; i <= Tm; ++ i) {
for(int j = 1; j <= Tn; ++ j) {
if((i + j) & 1) {
for(int k = 0; k <= 3; ++ k) {
int ni = i + nx[k];
int nj = j + ny[k];
if(ni < 1 || nj < 1 || ni > Tm || nj > Tn) continue;
add((i-1)*Tn+j,(ni-1)*Tn+nj,INF);
add((ni-1)*Tn+nj,(i-1)*Tn+j,0);
}
}
}
}
cout << sum - get_maxflow();
return 0;
}
代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct node {
int to, next, len;
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
e[cnt] = {to,head[from],len};
head[from] = cnt ++;
}
int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];
bool bfs() {
ms(d,0);
queue<int> q;
q.push(s); d[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[v] || e[i].len <= 0) continue;
q.push(v);
d[v] = d[u] + 1;
}
}
for(int i = 0; i <= n; ++ i) cur[i] = head[i];
return d[t] != 0;
}
int dfs(int u, int flow) {
if(u == t) return flow;
for(int &i = cur[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
int delta = dfs(v,min(flow,e[i].len));
if(delta <= 0) continue;
e[i].len -= delta;
e[i^1].len += delta;
return delta;
}
return 0;
}
int get_maxflow() {
int maxFlow = 0, delta;
while(bfs())//bfs进行构建最短路网络
while(delta = dfs(s,INF))
maxFlow += delta;
return maxFlow;
}
int Tn, Tm;
int Map[202][202];
int nx[] = {2,2,-2,-2,-1,-1,1,1};
int ny[] = {-1,1,-1,1,2,-2,2,-2};
int sum = 0;
int main() {
IOS;
ms(head,-1);
cin >> Tn >> Tm;
for(int i = 1; i <= Tm; ++ i) {
int x, y;
cin >> x >> y;
Map[x][y] = 1;
}
s = 0, t = Tn * Tn + 1;
n = t;
for(int i = 1; i <= Tn; ++ i) {
for(int j = 1; j <= Tn; ++ j) {
if(Map[i][j]) continue;
if((i+j)&1) add(s,(i-1)*Tn+j,1), add((i-1)*Tn+j,s,0);
else add((i-1)*Tn+j,t,1), add(t,(i-1)*Tn+j,0);
}
}
int sum = Tn * Tn;
for(int i = 1; i <= Tn; ++ i) {
for(int j = 1; j <= Tn; ++ j) {
if((i+j)&1 && !Map[i][j]) {
for(int k = 0; k < 8; ++ k) {
int ni = i + nx[k];
int nj = j + ny[k];
if(Map[ni][nj] || ni < 1 || nj < 1 || ni > Tn || nj > Tn) continue;
add((i-1)*Tn+j,(ni-1)*Tn+nj,INF);
add((ni-1)*Tn+nj,(i-1)*Tn+j,0);
}
}
}
}
cout << sum - get_maxflow() - Tm;
return 0;
}