"LibreOJ Round #11" Misaka Network and test (bipartite graph matching + network flow)

description

The researchers wanted to test the Misaka Network, so they gathered all the sisters in the Misaka Network together.
Now the sisters are arranged in N rows and M columns, and some positions are empty. Now researchers have assessed the superpowers of each individual. There are three levels of ability: Level 1 low-powered, Level 2 superpowered, and Level 3 superpowered. Researchers can select all individuals in a sub-rectangle for each test. In order to ensure high efficiency, they do not want empty positions in this rectangle. And, in order to ensure stability, they hope that the average of the ability levels of all individuals in this rectangle is exactly 2. At the same time, each individual can only participate in one test at most, so the rectangles selected for multiple tests should not intersect.

Researchers want to know how many tests they can perform at most.

Input format The
first line of two integers N, M and the
next N lines have M characters in each line, and each character represents an individual at a corresponding position in the queue.
1 means Level 1 with low abilities, 2 means Level 2 with super powers, 3 means Level 3 with super powers, and * means an empty position.

Output format
One integer per line indicates how many tests can be performed at most.
Example 1
Input
2 3
31*
*13
Output
2

Example 2
Input
6 6
23311*
**13**
11*233
13*223
***133
331***
Output
9

Sample 3
Input
2 50
21111121332233123311312211231333122233133212221212
21332123132223111331233121122331133311112121331311
Output
51

Data range and tips
For all data 1≤N×M≤10^5, the queue only contains four characters of 1, 2, 3, and *.

solution

The average is 2 22 , it’s not hard to think of1, 3 1, 31,3 must be one-to-one binding
and2 22 must be a single matrix (optimal),
so only consider1, 3 1, 31,3 make up a pair, the obvious bipartite graph matching problem
will be adjacent1, 3 1, 31,Connect 3 sides, then run the bipartite graph maximum match, Hungary’sn 3 n^3n3 is unbearable,
so I invited our old friend-network flow running bipartite graph maximum matching

Will sss and1 1The flow rate of1connection is1 11 side, adjacent1 − 3 1-313 continuous flow rate is1 11 side,3 33 andttt connected flow rate is1 11 side
Insert picture description here

code

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005
#define inf 1e9
struct node {
    
    
	int nxt, to, flow;
}edge[maxn << 2];
queue < int > q;
int n, m, cnt;
char str[2][maxn];
int head[maxn], cur[maxn], dep[maxn];

void addedge( int u, int v, int w ) {
    
    
	edge[cnt].nxt = head[u];
	edge[cnt].to = v;
	edge[cnt].flow = w;
	head[u] = cnt ++;
	
	edge[cnt].nxt = head[v];
	edge[cnt].to = u;
	edge[cnt].flow = 0;
	head[v] = cnt ++;
}

bool bfs( int s, int t ) {
    
    
	memcpy( cur, head, sizeof( head ) );
	memset( dep, 0, sizeof( dep ) );
	q.push( s ), dep[s] = 1;
	while( ! q.empty() ) {
    
    
		int u = q.front(); q.pop();
		for( int i = head[u];~ i;i = edge[i].nxt ) {
    
    
			int v = edge[i].to;
			if( ! dep[v] && edge[i].flow ) {
    
    
				dep[v] = dep[u] + 1;
				q.push( v );
			}
		}
	}
	return dep[t];
}

int dfs( int u, int t, int cap ) {
    
    
	if( u == t || ! cap ) return cap;
	int flow = 0;
	for( int i = cur[u];~ i;i = edge[i].nxt ) {
    
    
		cur[u] = i;
		int v = edge[i].to;
		if( dep[v] == dep[u] + 1 ) {
    
    
			int w = dfs( v, t, min( cap, edge[i].flow ) );
			if( ! w ) continue;
			cap -= w;
			flow += w;
			edge[i].flow -= w;
			edge[i ^ 1].flow += w;
			if( ! cap ) break;
		}
	}
	return flow;
}

int dinic( int s, int t ) {
    
    
	int ans = 0;
	while( bfs( s, t ) )
		ans += dfs( s, t, inf );
	return ans;
}

int id( int i, int j ) {
    
    
	return ( i - 1 ) * m + j;
}

int main() {
    
    
	memset( head, -1, sizeof( head ) );
	scanf( "%d %d", &n, &m );
	int s = 0, t = n * m + 1, tot = 0;
	for( int i = 1;i <= n;i ++ ) {
    
    
		int k = i & 1;
		scanf( "%s", str[k] + 1 );
		for( int j = 1;j <= m;j ++ ) {
    
    
			int pos = id( i, j );
			switch( str[k][j] ) {
    
    
				case '*' : {
    
     break; }
				case '1' : {
    
    
					addedge( s, pos, 1 );
					if( i != 1 && str[k ^ 1][j] == '3' )
						addedge( pos, pos - m, 1 );
					if( j != 1 && str[k][j - 1] == '3' )
						addedge( pos, pos - 1, 1 );
					if( j != m && str[k][j + 1] == '3' )
						addedge( pos, pos + 1, 1 );
					break;
				}
				case '2' : {
    
     tot ++; break; }
				case '3' : {
    
    
					addedge( pos, t, 1 );
					if( i != 1 && str[k ^ 1][j] == '1' )
						addedge( pos - m, pos, 1 );
					break;
				}
			}
		}
	}
	printf( "%d\n", tot + dinic( s, t ) );
	return 0;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113718465