UVA 10092 The Problem with the Problemsetter【二分图最大匹配变形 邻接矩阵实现最大匹配算法】

题目大意:一名老师出题,要求出N种题型,每个题型要求出多少题给出;

                    现在有M道题(待选问题),每道题给出它可以被归类的题型;

                    问最后是否能按照要求出题,满足要求,输出1及每种题型对应待选问题,否则输出0

解题策略:这题初看思路与 UVA 11045 My T-shirt suits me http://blog.csdn.net/j_dark/article/details/8830539相同,

                    1, 由于每种题型有容量要求,故考虑将题型size拆成题型同为size的k道题(若该种题型要求出k道),

                           建立{题型拆后题,待选问题}二部图模型;

                    2,判别能否按要求出题——求出待选题目相对题型的最大匹配(逻辑上可理解为按照题型能够出多少题),与要求出题数比较,

                          感觉 上述最大匹配数<=要求出题数,未证明(网上都是网络流的报告,学过网络流后,估计会多一种理解。)

                    3,用sizeMatch[i]记录与题型拆后题匹配的待选问题,这部分如何输出详见注释。

                    4,用邻接矩阵练了下最大匹配算法,发现在输出答案与运算时间方面,和邻接表不是一个时间量级。


/*
   UVA 10092 The Problem with the Problemsetter
   AC by J_Dark
   ON 2013/4/21
   Time 0.334s  邻接矩阵还真是慢
*/
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
const int maxn = 1005;
using namespace std;
/*
   1.  proSizeNum 题型数
	   proNum  待选问题数
	   proSizeSum  一共需出题数(各题型数目之和)

   2.  proSetNum[]  题型对应出题数
       proMatch[] 与待选问题匹配的拆后题型问题
       sizeMatch[]  与拆后题型问题匹配的待选问题
       proMatch[]与sizeMatch[]不同!

   3. 若一种题型要出第k种题,将一种题型拆成k种同题型题,建立拆后题型题——待选题二部图
       pos[i]存放第i种题型题在无向图g中起始下标,终点为pos[i]+proSetNum[i]
*/
int proSizeNum, proNum, proSizeSum;
int proSetNum[maxn], pos[maxn], g[maxn][maxn], proMatch[maxn], sizeMatch[maxn];
bool visited[maxn];

void Initial(){
	memset(g, 0, sizeof(g));
	pos[1] = 1;
	for(int i=2; i<=proSizeNum; i++){
		pos[i] = pos[i-1]+proSetNum[i-1];
	}
}

bool findPath(int u){
	for(int i=1; i<=proSizeSum; i++){
		if(g[u][i] && !visited[i]){
			visited[i] = true;
			if(sizeMatch[i] == -1 || findPath(sizeMatch[i])){
				sizeMatch[i] = u;
	            proMatch[u] = i;
				return true;
			}
		}
	}
	return false;
}

void MaxMatch(){
	for(int i=1; i<=proNum; i++)  proMatch[i] = -1;
	for(int i=1; i<=proSizeSum; i++)  sizeMatch[i] = -1;
	int maxMatch = 0;
	for(int i=1; i<=proNum; i++){
		if(proMatch[i] == -1){
			memset(visited, false, sizeof(visited));
			if(findPath(i))
			   maxMatch++;
		}
	}

	//若最大匹配数即最大可以出题数与要求出题数相同,则输出相应答案
	if(maxMatch == proSizeSum){
		cout << 1 << endl;
	    for(int i=1; i<=proSizeNum; i++){
		   //输出与第i种题型匹配的proSet[i]道待选题
	       for(int k=0; k<proSetNum[i]; k++){
	          if(k>0)  cout << " ";
	          cout << sizeMatch[pos[i]+k];
	       }
	       cout << endl;
	    }
	}
	else cout << 0 << endl;
}
///////////////////////////////////////////////////////////////
int main(){
	while(cin >> proSizeNum >> proNum && (proSizeNum||proNum))
	{
		proSizeSum = 0;
		for(int i=1; i<=proSizeNum; i++){
		   cin >> proSetNum[i];
		   proSizeSum += proSetNum[i];
		}
		Initial();
		for(int i=1; i<=proNum; i++){
			int reachedNum;
			cin >> reachedNum;
			for(int j=0; j<reachedNum; j++){
				int v;
				cin >> v;
				//将一种题型v拆成k种题型为v题
				for(int k=0; k<proSetNum[v]; k++)
				   g[i][pos[v]+k] = v;
			}
		}
		MaxMatch();
	}
	//system("pause");
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章