「LibreOJラウンド#11」御坂ネットワークとテスト(2部グラフマッチング+ネットワークフロー)

説明

研究者たちは御坂ネットワークをテストしたかったので、御坂ネットワークのすべての姉妹を集めました。
これで、姉妹はN行M列に配置され、一部の位置は空になります。現在、研究者は各個人の超大国を評価しています。能力には、レベル1の低出力、レベル2の超大国、レベル3の超大国の3つのレベルがあります。研究者は、テストごとにサブ長方形内のすべての個人を選択できます。高効率を確保するために、研究者はこの長方形内の空の位置を望んでいません。そして、安定性を確保するために、彼らはこの長方形のすべての個人の能力レベルの平均が正確に2であることを望んでいます。同時に、各個人は最大で1つのテストにしか参加できないため、複数のテスト用に選択された長方形が交差しないようにする必要があります。

研究者は、最大で実行できるテストの数を知りたいと考えています。

入力形式
2つの整数N、M最初の行と
次のN行には、各行にM文字があり、各文字はキュー内の対応する位置にある個人を表します。
1は能力の低いレベル1を意味し、2はスーパーパワーのレベル2を意味し、3はスーパーパワーのレベル3を意味し、*は空の位置を意味します。

出力形式
1行に1つの整数は、最大で実行できるテストの数を示します。
例えば1
入力
2 3
31 *
* 13
出力
2

実施例2
入力
6 6
23311 *
** 13 **
11 * 233
13 * 223
*** 133
331 ***
出力
9

サンプル3
入力
2 50
21111121332233123311312211231333122233133212221212
21332123132223111331233121122331133311112121331311
出力
51

データ範囲とヒント
すべてのデータ1≤N×M≤10^ 5の場合、キューには1、2、3、および*の4文字のみが含まれます。

解決

平均である2 22、それは考えるために難しいことではありません、1 3 1 31 図3は、である必要があり一対一の結合
及び2 22は単一の行列(最適)でなければならない
ため、1、3 1、3のみを考慮してください。1 3がペアを構成する場合、明らかな2部グラフのマッチング問題
は隣接します1、3 1、31 3つの辺を接続してから、2部グラフの最大一致を実行します。ハンガリーのn 3 n ^ 3n3は耐えられない
ので2部グラフの最大マッチングを実行する古い友人ネットワークフローを招待しました

ウィルSSsおよび111接続流量は11です。1つの側、隣接1 - 3 1-313連続流量は111つの側、3 33ttt接続流量は11です1
ここに画像の説明を挿入します

コード

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

おすすめ

転載: blog.csdn.net/Emm_Titan/article/details/113718465