【2018年8省合同試験】分割(ハンガリー)

説明

毎年恒例のバラエティ番組「中国の新法典」が再開されました。Zayidは子供の頃からプログラマーになることを夢見ていましたが、これは自分を披露するステージだと感じたので、ためらうことなくサインアップしました。

道路に詳しいザイドはオーディションに合格し、次のステップはインストラクターによるブラインドセレクションです。このステージのルールは次のとおりです
。合計n人の競技者(1からnまでの番号)がそれぞれコードを書き、自分自身に夢を紹介します。次に、すべてのインストラクターがこれらのプレーヤーをランク付けします。その後のトラブルを避けるため、タイインランキングはありません。

同時に、各出場者は独立してボランティアフォームに記入し、合計m人のチューター(1からmまでの番号)を評価します。合計m個のボランティアのファイルがボランティアリストに含まれています。ボランティアのレベルごとに、プレーヤーは最大C人のチューターを記入でき、各チューターは各プレーヤーが最大1回記入できます(一部のチューターを放棄することもできます)。

両当事者の作業が完了した後、入学作業が行われます。各メンターには、自分のチームのチーム数に上限があります。つまり、一部のプレーヤーは、上位のボランティア、またはすべてのボランティアに会うことができない場合があります。

プログラムグループは、「トップiの最高の入学結果」を次のように定義しています。
トップ1は、1位が最も高い空でないボランティアによって承認された場合にのみ、最高の入学結果を示します(特に、1位の場合)。ボランティアフォームに記入されていない場合、プレーヤーは退場しています)。
トップi-1の入学結果が最高である場合に限り、トップiの入学結果が最高です。i番目の場所は、理論的に可能な最高の場所に受け入れられます(特に、i番目の場所の場合)。テーブル内のメンターチーム、またはそのすべてのボランティアが採用されている場合、プレーヤーは不在です)。

スキームが「上位nの最良の入学結果」を満たす場合、このスキームを最適と省略できます。

たとえば、2人のインストラクターであるTeacherTとTeacherFのチームサイズの上限はそれぞれ1つであり、2人のプレーヤーZayidとDuckDはそれぞれ1位と2位にランク付けされています。次に、次の3種類のボランティアリストとそれに対応する最適な入学結果を表に示します。
ここに画像の説明を挿入しますここに画像の説明を挿入します

上記のボランティアリストでは、対応するプログラムが唯一の最適な入学結果であることが証明できます。
誰もが自分の理想的な価値siを持っているので、i番目の学生はsi番目以上のボランティアに入学したいと思っています。そうでない場合、彼は非常にイライラします。
現在、ボランティアリストと全選手のランキングが公開されています。偶然にも、各プレイヤーのランキングはたまたま彼らの数と同じです。
Zayidは、すべてのプレーヤーについて、次の2つの質問に対する答えを知りたいと考えています。
最良の入学計画では、どのボランティアが入学するか。
他のプレイヤーの相対的なランキングは変更されていませんが、少なくとも彼をイライラさせないためにいくつの場所が上がることができます。
「ChinaNewCode」の強力なコードプレーヤーとして、Zayidは確かにこの問題を簡単に解決しました。しかし、彼は
まだあなたに彼の計算の正しさをチェックするためにもう一度計算をすることを望んでいます。

入力形式
各テストポイントには、複数のテストデータセットが含まれています。最初の行でスペースで区切られた2つの非負の整数TとCは、
データセットの数とボランティアの各ファイルに入力できるチューターの最大数を示します。

次に、データの各グループについて、データの各グループを順番に記述
します。スペースで区切られた2つの正の整数n、m最初の行です。
nとmは、それぞれプレーヤーの数とメンターの数を表します。

2行目でスペースで区切られたM個の正の整数:i番目の整数はbiです。
biは、チューターチーム番号iの数の上限を表します。

3行目からn + 2行目まで、各行にはスペースで区切られたm個の非負の整数があります。i+ 2行目の左からj番目の数値はai、jです。
ai、jは、番号iのプレーヤーが、番号jのインストラクターをai、j番目のボランティアに配置することを意味します。特に、ai、j = 0の場合、プレイヤーがボランティアリストに講師を記入しなかったことを意味します。この部分では、各行にC回を超えて発生する正の数がないことを確認し(0はC回を超えて発生する可能性があります)、すべてのai、j≤mを確認します

行n + 3スペースで区切られたn個の正の整数。ここで、i番目の整数はsiです。
siは、プレーヤー番号iの理想的な値を表します。この部分では、si≤mであることを確認してください

出力形式
各データグループの回答を順番に出力します。データの各セットについて、2行を出力します。
最初の行はスペースで区切られたn個の正の整数を出力します。ここで、i番目の整数の意味は次のとおり
です。最適な入場プランでは、iという番号のプレーヤーがこのファイル入場によって志願されます。
特に、プレーヤーが外出している場合、この数はm +1です。

2行目は、スペースで区切られたn個の非負の整数を出力します。i番目の整数の意味は
、プレーヤー番号iをイライラさせないようにすること、および少なくともプレーヤーを上げるために必要なランク数にすることです。
特に、プレイヤーがイライラしなければならない場合、この数字はiです

サンプル1

3 5
2 2
1 1
2 2
1 2
1 1
2 2
1 1
1 2
1 2
2 1
2 2
1 1
0 1
0 1
2 2

	

2 1
1 0
1 2
0 1
1 3
0 1

3セットのデータは、「トピックの説明」の3つの表に対応しています。

最初のデータセットの場合:プレーヤー1は最初の選択肢を入力しなかったため、最初の選択肢を
認めてはなりません。間違いなくイライラします。プレイヤー2は元のランキングに不満を感じていないため、ランキングを上げる必要はありません。
2番目と3番目のグループデータの場合:1位のプレーヤーはランキングを上げる必要はありません。そして、最初の選択肢に受け入れられることを望む第2のプレーヤーは、そうするために最初の場所に昇進しなければなりません。

サンプル2

1 5
4 3
2 1 1
3 1 3
0 0 1
3 1 2
2 3 1
2 3 3 3

	

1 1 3 2
0 0 0 0

出場者No.1の最初の選択肢はメンターNo.2にのみ記入されているため、出場者No.1はメンターNo.2によって承認される必要があります。
出場者No.2は、最初の選択肢としてメンターNo. 3のみを記入するため、出場者No.2はメンターNo.3によって承認される必要があります。
No.2とNo.3のチューターは全員満員で、No.3とNo.4の出場者はNo.1のチューターを記入しているので、全員がNo.1のチューターに受け入れられます。
したがって、出場者1と2は最初のボランティアによって入場され、出場者No. 3は3番目のボランティアによって入場され、出場者No.4は2番目のボランティアによって入場されました。
彼らは皆彼らが望むものを手に入れたので、彼らは彼らのランキングを改善する必要はありません。

データ範囲とヒント
すべてのテストポイントについて、T≤5であることを確認します。
すべてのテストポイントのすべてのデータについて、m≤n≤200、bi≤nであることを確認します。

解決

ハンガリーのアルゴリズムも(ఠൠఠ)ノ!
ここに画像の説明を挿入します
各競技者の自主的な列を良いものから悪いものへと直接列挙してから、そのボランティアの特定のインストラクターとペアリングしてみてください。
インストラクターにまだ割り当てがある場合は、割り当てに直接参加して
、インストラクターを列挙しているすべての生徒に確認してもらいます。彼らは行くことができます。
このプレーヤーのための場所を作るために同等のステータスの別のインストラクターを選択してください
プロセスはハンガリーで実行できます。
最小の昇進については?
非常に巧妙に、ハンガリーを実行するときは、xxxが一致するメンターを変更する場合、実際には、現在のプレーヤーがxxを置き換える場合を意味します。x、彼はxxに一致することができますxがメンターと一致
するようになったため、ハンガリーのプロセスで拡張されたxxを要求するだけで済みます。x番号
の最大値から現在のプレーヤー番号の最大値を引いたが最小の昇順位置です

コード

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 205
int T, C, n, m, now, maxx;
int lim[maxn], s[maxn], match[maxn], id[maxn], minn[maxn];
int tot[maxn][maxn];//tot[i][j] i选手的第j志愿一共填了多少导师 
int wish[maxn][maxn][maxn];//wish[i][j][k] i选手的第j志愿栏选的第k位导师
bool vis[maxn];

bool find( int u, int k ) {
    
    
	if( u < now ) maxx = max( maxx, u );
	for( int i = 1;i <= tot[u][k];i ++ ) {
    
    
		int v = wish[u][k][i]; //枚举k支援栏i选手属于的导师
		if( vis[v] ) continue;
		vis[v] = 1;
		if( lim[v] ) {
    
    //如果v导师还有名额 直接进入 
			match[u] = v;
			id[u] = k;
			lim[v] --;	
			return 1; 
		} 
		for( int j = 1;j <= n;j ++ ) {
    
    //枚举v导师集合中的其他选手 看能不能换等地位的导师阵营 让u成为v导师人员 
			if( j == u || match[j] != v ) continue;
			if( find( j, id[j] ) ) {
    
    
				match[u] = v;
				id[u] = k;
				return 1;
			}
		}
	}
	return 0;
}
 
int main() {
    
    
	scanf( "%d %d", &T, &C ); 
	while( T -- ) {
    
    
		memset( tot, 0, sizeof( tot ) );
		memset( wish, 0, sizeof( wish ) );
		memset( match, 0, sizeof( match ) ); 
		scanf( "%d %d", &n, &m );
		for( int i = 1;i <= m;i ++ )
			scanf( "%d", &lim[i] );
		for( int i = 1;i <= n;i ++ )
			for( int j = 1, rnk;j <= m;j ++ ) {
    
    
				scanf( "%d", &rnk );
				if( ! rnk ) continue;
				else wish[i][rnk][++ tot[i][rnk]] = j;
			}
		for( int i = 1;i <= n;i ++ )
			scanf( "%d", &s[i] );
		for( int i = 1;i <= n;i ++ )
			id[i] = m + 1, minn[i] = i;
		for( int i = 1;i <= n;i ++ ) {
    
    
			memset( vis, 0, sizeof( vis ) );
			now = i; 
			for( int j = 1;j <= m;j ++ ) {
    
    
				if( ! tot[i][j] ) continue; //第j志愿栏为空 跳过
				maxx = 0;
				if( find( i, j ) ) {
    
     //i选手可以成为j志愿栏里某导师的学员 
					if( j <= s[i] ) minn[i] = 0;
					break;
				}
				if( j <= s[i] ) minn[i] = min( minn[i], i - maxx );
			}
		}
		for( int i = 1;i <= n;i ++ )
			printf( "%d ", id[i] );
		printf( "\n" );
		for( int i = 1;i <= n;i ++ )
			printf( "%d ", minn[i] );
		printf( "\n" );
	}
	return 0;
}

おすすめ

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