1. 程式人生 > >【BZOJ4375】Selling Tickets 隨機化

【BZOJ4375】Selling Tickets 隨機化

line 賣出 ets -s 每次 感到 mil 分隔 針對

【BZOJ4375】Selling Tickets

Description

廚師在一次晚宴上準備了n道豐盛的菜肴,來自世界各地的m位顧客想要購買宴會的門票。每一位顧客都有兩道特別喜愛的菜,而只要吃到了至少一道他喜愛的菜,這位顧客就會感到很高興。當然,每道菜最多只能供應給一位顧客。廚師想要賣出盡可能多的門票,但同時要能夠保證,無論哪些顧客購買門票,所有到來的顧客都能感到高興。現在,廚師想要問你,他最多能夠賣多少門票?

Input

輸入的第一行包含一個正整數T,表示數據組數。
對於每組數據,第一行包含一對整數n和m,分別表示菜肴的數量與顧客的數量。接下來m行,第i行的兩個正整數Ai, Bi代表第i位顧客喜愛的兩道菜的編號。相鄰的兩組數據之間用一個空行分隔。

Output

輸出總共T行,對於每組數據,輸出一個整數,表示廚師最多能售出的門票數。

Sample Input

3
6 4
1 2
1 2
3 4
5 6

6 5
1 2
1 2
1 2
3 4
5 6

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

Sample Output

4
2
4

HINT

對於第二組數據,廚師不能賣3張門票。因為如果顧客1, 2, 3購買門票,廚師是不可能用菜肴1, 2滿足三個顧客的要求的。
【數據規模與約定】
1≤T≤15, 2≤n≤200, 0≤m≤500

1≤Ai, Bi≤n且Ai≠Bi

題解:我想不出正解,居然采用隨機化;並且隨機化寫掛了,還針對數據進行隨機化,我真是太無恥了~

簡單的想法就是每次random_shuffle一個序列,沿著這個序列從左到右一直賣,如果賣到第i+1個賣不出去了,就用i更新答案。如何判定能不能賣出去呢?二分圖最大匹配即可。

但是這種隨機化策略實在是naive,我們考慮優化,如果賣到i+1個賣不出去了,我們看一下第i+1個人在二分圖最大匹配上一共試圖匹配了多少個人,即交錯環的大小。並用交錯環的大小來更新答案,然後就切了~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,S,T,ans,cnt,now,sum;
int A[510],B[510],vis[510],head[1010],p[1010],to[10010],next[10010],from[210];
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int dfs(int x)
{
	sum++;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(vis[to[i]]!=now)
		{
			vis[to[i]]=now;
			if(!from[to[i]]||dfs(from[to[i]]))
			{
				from[to[i]]=x;
				return 1;
			}
		}
	}
	return 0;
}
void work()
{
	srand(1011);
	n=rd(),m=rd(),ans=m;
	int i,j,a,b;
	memset(head,-1,sizeof(head)),cnt=0,memset(vis,0,sizeof(vis)),now=0;
	for(i=1;i<=m;i++)	a=rd(),b=rd(),add(i,a),add(i,b),p[i]=i;
	for(i=1;i<=2000;i++)
	{
		random_shuffle(p+1,p+m+1);
		memset(from,0,sizeof(from));
		for(j=1;j<=m;j++)
		{
			now++,sum=0;
			if(!dfs(p[j]))
			{
				ans=min(ans,sum-1);
				break;
			}
		}
	}
	printf("%d\n",ans);
}
int main()
{
	int T=rd();
	while(T--)	work();
	return 0;
}//3 6 4 1 2 1 2 3 4 5 6 6 5 1 2 1 2 1 2 3 4 5 6 4 5 1 2 1 3 1 4 2 3 3 4

【BZOJ4375】Selling Tickets 隨機化