2289

/*
1000个联系人 N

500个群 M

使得最大那个群的人数最少,

每个人都可以去好几个群,这样就有很多选择了。每个群最多有 N个人,所以二分答案
然后建图,看是否满足条件,最后找到一个最佳答案

初试的想法WA,所以现在用笨的方法,人数和群都算顶点,这样就有1502个点,矩阵不行了,邻接表上
,最快的方法是二分+二分图多重匹配。 不过我暂时只是练习网络流了
*/

// include file
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <ctime>

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <bitset>

#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <list>
#include <functional>

using namespace std;

// typedef
typedef long long LL;
typedef unsigned long long ULL;
typedef __int64 Bint;

// 
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#define FORi(a,b,c) for(int i=(a);i<(b);i+=c)
#define FORj(a,b,c) for(int j=(a);j<(b);j+=c)
#define FORk(a,b,c) for(int k=(a);k<(b);k+=c)
#define FORp(a,b,c) for(int p=(a);p<(b);p+=c)
#define FORii(a,b,c) for(int ii=(a);ii<(b);ii+=c)
#define FORjj(a,b,c) for(int jj=(a);jj<(b);jj+=c)
#define FORkk(a,b,c) for(int kk=(a);kk<(b);kk+=c)

#define FF(i,a)    for(int i=0;i<(a);i++)
#define FFD(i,a)   for(int i=(a)-1;i>=0;i--)

#define Z(a) (a<<1)
#define Y(a) (a>>1)

const double eps = 1e-6;
const double INFf = 1e10;
const int INFi = 1000000000;
const double Pi = acos(-1.0);

template<class T> inline T sqr(T a){return a*a;}
template<class T> inline T TMAX(T x,T y)
{
	if(x>y) return x;
	return y;
}
template<class T> inline T TMIN(T x,T y)
{
	if(x<y) return x;
	return y;
}
template<class T> inline void SWAP(T &x,T &y)
{
	T t = x;
	x = y;
	y = t;
}
template<class T> inline T MMAX(T x,T y,T z)
{
	return TMAX(TMAX(x,y),z);
}

// tool function

// code begin
#define MAXN 1600
#define MAXM 510000

struct node1
{
	int e;
	int next;
	int remain;
};

node1 mem[MAXM];
node1 memb[MAXM];
int dx;
int dxb;

class MaxFlow_ISAP_link
{
private:
	int N,source,sink;
	int G[MAXN];           //图的正向连接
	int GB[MAXN];          //图的反向连接
	int stk[MAXN],top;   
	int que[MAXN];
	int dis[MAXN]; //距离
	int lay[MAXN]; //层个数
	int pos[MAXN]; //当前弧
	int fat[MAXN]; //


public:
	MaxFlow_ISAP_link(){};
	
	void Set(int Nt,int sourcet,int sinkt)
	{
		N = Nt;
		source = sourcet;
		sink = sinkt;
	}
	
	void Init()
	{
		dx = 0;
		memset(G,-1,sizeof(G));		
	}

	void Back()
	{
		memcpy(memb,mem,sizeof(node1)*(dx+1));
		memcpy(GB,G,sizeof(int)*(N+1));
		dxb = dx;
	}

	void Reuse()
	{
		memcpy(mem,memb,sizeof(node1)*(dxb+1));
		memcpy(G,GB,sizeof(int)*(N+1));
		dx = dxb;
	}
	
	void Print()
	{
		FORi(1,N+1,1)
		{
			printf("%d: ",i);
			int mdx = G[i];
			while(mdx!=-1)
			{
				printf("[%d %d] ",mem[mdx].e,mem[mdx].remain);
				mdx = mem[mdx].next;
			}
			printf("\n");
		}
		printf("\n");
	}
	
	void Add_edge(int a,int b,int c)
	{
		mem[dx].e = b;
		mem[dx].next = G[a];
		mem[dx].remain = c;
		G[a] = dx ++;

		mem[dx].e = a;
		mem[dx].next = G[b];
		mem[dx].remain = 0;
		G[b] = dx ++;
	}

	void CalDis(int a,int b)
	{
		memset(lay,0,sizeof(lay));

		/*
		FORi(1,a+1,1)
		{
			dis[i] = 2;
		}
		*/
		fill(dis+1,dis+a+1,2);
		lay[2] = a;
		/*
		FORi(1,b+1,1)
		{
			dis[i+a] = 1;
			lay[1]++;
		}
		*/
		fill(dis+a+1,dis+a+b+1,1);
		lay[1] = b;
		dis[source] = 3;
		lay[3]++;
		dis[sink] = 0;
		lay[0]++;
	}
public:
/*
	void BFS()
	{
		int head(0),tail(0);
		fill(dis,dis+N+1,N);
		fill(lay,lay+N+1,0);
		FORi(1,N+1,1)
		{
			lay[dis[i]]++;
		}

		//
		lay[dis[sink]]--;
		dis[sink] = 0;
		lay[dis[sink]]++;

		que[++tail] = sink;
		
		int mdx;
		while(head!=tail)
		{
			int cur = que[++head];
			mdx = RG[cur];
			while(mdx!=-1)
			{
				int v = Rmem[mdx].e;
				if( dis[v]==N && Rmem[mdx].remain!=0 )
				{
					lay[ dis[v] ]--;
					dis[v] = dis[cur]+1;
					lay[ dis[v] ]++;
					
					que[++tail] = v;
				}

				mdx = Rmem[mdx].next;
			}
		}
	
	}
*/
	int Augment()
	{
		int minp = INFi;

		FORi(0,top,1)
		{
			if(mem[stk[i]].remain<minp)
				minp = mem[stk[i]].remain;
		}

		FORi(0,top,1)
		{
			mem[stk[i]].remain -= minp;
			mem[(stk[i]&1)?(stk[i]-1):(stk[i]+1)].remain += minp;
		}

		return minp;
	}

	int Relabel(int &cur)
	{
		int tmp;
		int mind(N-1);
		
		int mdx = G[cur];
		while(mdx!=-1)
		{
			if( mem[mdx].remain>0 && dis[ mem[mdx].e ]<mind)
				mind = dis[ mem[mdx].e ];
			mdx = mem[mdx].next;
		}

		tmp = dis[cur];

		lay[dis[cur]]--;
		dis[cur] = 1+mind;
		lay[dis[cur]]++;

		if(cur!=source)
		{
			cur = fat[cur];
			top --;
		}

		return lay[tmp];
	}

	int Maxflow()
	{
		int flow(0);

//		BFS();

		memcpy(pos,G,sizeof(G));

		top = 0;

		int st = source;

		while(dis[source]<N)
		{
			//
			int ds=-1,dsmx,mdx;
			mdx =pos[st];
			while(mdx!=-1)
			{
				int v = mem[mdx].e;
				if( mem[mdx].remain>0 && dis[st]==dis[v]+1 )
				{
					ds = v;
					dsmx = mdx;
					break;
				}

				mdx = mem[mdx].next;
			}
			
			if(ds!=-1)
			{

				pos[st] = dsmx;
				stk[top++] = dsmx;
				
				fat[ds] = st;
				st = ds;

				if(st==sink)
				{
					flow += Augment();
					st = source;
					top = 0;
				}
			}
			else
			{
				pos[st] = G[st];
				if( Relabel(st) == 0 )
					break;
			}
		}

		return flow;
	}
};

int N,M,source,sink;
MaxFlow_ISAP_link g;

char name[20];

int gp;

int main()
{
	read;
	write;
	while(scanf("%d %d",&N,&M)!=-1)
	{
		if(N+M==0) break;
		source = N+M+1;
		sink = N+M+2;
		g.Init();
		g.Set(N+M+2,source,sink);
		getchar();
		FORi(1,N+1,1)
		{
			scanf("%s",name);
			
			do
			{
				scanf(" %d",&gp);
				g.Add_edge(i,gp+1+N,1);	
			}while(getchar()!='\n');

			g.Add_edge(source,i,1);
		
		}

		int L = 0,R = N+1,ans=INFi,mf;
		g.Back();
		while(L<R)
		{
			int mid = Y(L+R);
			
			FORi(1,M+1,1)
			{
				g.Add_edge(i+N,sink,mid);
			}
			g.CalDis(N,M);
			//g.Print();
			mf = g.Maxflow();
			//printf("最大流 %d\n",mf);
			if(mf<N)
			{
				L = mid+1;
			}
			else
			{
				if(mid<ans) ans=mid;
				R = mid;
			}
			g.Reuse();
		}

		printf("%d\n",ans);
	}
	return 0;
}

posted @ 2011-03-17 17:16  AC2012  阅读(361)  评论(0编辑  收藏  举报