/*
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;
}
转载于:https://www.cnblogs.com/ac2012/archive/2011/03/17/1987279.html