1. 程式人生 > >hdu 3605 Escape 二分圖的多重匹配(匈牙利演算法)

hdu 3605 Escape 二分圖的多重匹配(匈牙利演算法)

Escape

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 8001    Accepted Submission(s): 1758
Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets.

Input More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet.
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000

Output Determine whether all people can live up to these stars
If you can output YES, otherwise output NO.

Sample Input 1 1 1 1 2 2 1 0 1 0 1 1
Sample Output YES NO
Source 題目大意: N(N<100,000)個人要去M(M<10)個星球,每個人只可以去一些星球,一個星球最多容納Ki個人,輸出是否所有人都可以選擇自己的星球。
解題思路:放置了很久的題目了,一直是TLE,今天翻出來改來改去還是TLE~~~~大哭大過年的,非要AC。 由於n很大,m很小,標記的陣列不要太大,15就足夠啦。解決多重匹配就是記錄一下多重匹配的點(簡稱Y方點)已經匹配了Pi個點。如果Pi<Ki那麼就直接上了,否則的話繼續搜尋Yi已經匹配的每一個點並將Yi染色,因為Yi搜一次就需要染色了,而且Y方點最多是10個,所以每次找增廣路的深度最多是10,這樣就很快了!!!吐舌頭(用c++交吧) 詳見程式碼。
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m;
int w[15],cnt[15];
int Map[100010][12],mat[12][100010];
bool vis[15];

bool Find(int x)
{
	for(int i=0;i<m;i++)
		if(!vis[i]&&Map[x][i])
		{
			vis[i]=1;
			if(cnt[i]<w[i])
			{
				mat[i][cnt[i]++]=x;
				return true;
			}
			for(int j=0;j<cnt[i];j++)
				if(Find(mat[i][j]))
				{
					mat[i][j]=x;
					return true;
				}
		}
	return false;
}

bool ok()
{
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(!Find(i))
			return false;
	}
	return true;
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				scanf("%d",&Map[i][j]);
		for(int i=0;i<m;i++)
			scanf("%d",&w[i]);
        if (ok()==1)
            printf ("YES\n");
        else
            printf ("NO\n");
	}
	return 0;
}