UVA 1345 Jamie's Contact Groups

题意:

  一些人,和他们可能加入的组号。问每个组,最小的最大人数是多少

分析:

  二分的是最大流的容量。设置一个超级源点,连向所有的人,容量为1。设置一个超级汇点,使所有的组连向超级汇点,二分的就是这里的容量(0~n)。然后根据题目给出的人和组的关系连接人和组,容量为1。二分时,若当前状态求出的最大流等于人数,则下界等于mid,若不等于,则上界等于mid。二分出的容量,就是组中的最小的最大人数。

输入:

3 2

John 0 1

Rose 1

Mary 1

5 4

ACM 1 2 3

ICPC 0 1

Asian 0 2 3

Regional 1 2

ShangHai 0 2

0 0

输出:

2

2

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <sstream>
using namespace std;
const int maxn=3010;
const int inf=1e9;
int n,m;
structEdge
{
    int u,v;
    int flow,cap;
    Edge(int uu,int cc,int fl,int ca):u(uu),v(cc),flow(fl),cap(ca)
    {

    }
};
vector<Edge>edge;
structISAP
{
    vector<int>G[maxn];
    vector<Edge>edge;
    int s,t;
    int d[maxn];
    int cur[maxn];
    int p[maxn];
    int num[maxn];
    int flow;
    void init()
    {
        for(int i=0;i<=n+m+1;i++)
            G[i].clear();
        s=0;
        t=n+m+1;
    }
    bool bfs()
    {
        memset(d,-1,sizeof(d));
        queue<int>q;
        q.push(t);
        d[t]=0;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=0;i<G[u].size();i++)
            {
                Edge& e=edge[G[u][i]];
                if(e.cap==0&&d[e.v]==-1)
                {
                    d[e.v]=d[u]+1;
					q.push(e.v);
                }
            }
        }
        return d[s]!=-1;
    }
    int Augment()
    {
        int x=t,a=inf;
        while(x!=s)
        {
            Edge& e=edge[p[x]];
            a=min(a,e.cap-e.flow);
            x=edge[p[x]].u;
        }
        x=t;
        while(x!=s)
        {
            edge[p[x]].flow+=a;
            edge[p[x]^1].flow-=a;
            x=edge[p[x]].u;
        }
        return a;
    }
    int maxflow(int s,int t)
    {
        this->s=s;
        this->t=t;
        flow=0;
        bfs();
        for(int i=0;i<=n+m+1;i++)
            num[d[i]]++;
        int x=s;
        memset(cur,0,sizeof(cur));
        while(d[s]<n+m+2)
        {
            if(x==t)
            {
                flow+=Augment();
                x=s;
            }
            bool ok=false;
            for(int i=cur[x];i<G[x].size();i++)
            {
                Edge& e=edge[G[x][i]];
                if(e.cap>e.flow&&d[x]==d[e.v]+1)
                {
                    ok=true;
                    p[e.v]=G[x][i];
                    cur[x]=i;
                    x=e.v;
                    break;
                }
            }
            if(!ok)
            {
                int k=n+m+1;
                for(int i=0;i<G[x].size();i++)
                {
                    Edge& e=edge[G[x][i]];
                    if(e.cap>e.flow)
                        k=min(k,d[e.v]);
                }
                if(--num[d[x]]==0)
                    break;
                num[d[x]=k+1]++;
                cur[x]=0;
                if(x!=s)
                    x=edge[p[x]].u;
            }
        }
        return flow;
    }
}solver;
char buffer[11000];
void add(int s,int t,int cap)
{
    edge.push_back(Edge(s,t,0,cap));
    edge.push_back(Edge(t,s,0,0));
    int x=edge.size();
    solver.G[s].push_back(x-2);
    solver.G[t].push_back(x-1);
}
void input()
{
    solver.init();
    int x;
    edge.clear();
    char ch[100];
    for (int i = 1 ; i <= n ; ++i)
    {
		add(0,i,1);
		scanf("%*s");
		gets(buffer);
		char * p = strtok(buffer, " ");
		while (p) {
			sscanf(p,"%d",&x);
			add(i,x+1+n,1);
			p = strtok(NULL," ");
		}
	}
    int sz=edge.size();
    for(int i=n+1;i<=n+m;i++)
    {
        sz+=2;
        solver.G[i].push_back(sz-2);
        solver.G[n+m+1].push_back(sz-1);
    }
}
void build(int up)
{
    solver.edge=edge;
    for(int i=n+1;i<=n+m;i++)
    {
        solver.edge.push_back(Edge(i,n+m+1,0,up));
		solver.edge.push_back(Edge(n+m+1,i,0,0));
    }
}
void solve()
{
    int left=1,right=n;
    int mid=(left+right)>>1;
    int ans=n;
    while(left<=right)
    {
        build(mid);
        if (solver.maxflow(0,n+m+1)==n)
        {
			right = mid-1;
			ans = min(ans,mid);
		}
		else
        {
			left = mid+1;
		}
		mid = (left+right)>>1;
    }
    printf("%d\n",ans);
}
int main()
{
	while(scanf("%d%d",&n,&m)==2,n+m)
	{
		input();
		solve();
	}
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <sstream>
using namespace std;
const int maxn=3010;
const int inf=1e9;
int n,m;
structEdge
{
    int u,v;
    int flow,cap;
    Edge(int uu,int cc,int fl,int ca):u(uu),v(cc),flow(fl),cap(ca)
    {

    }
};
vector<Edge>edge;
structISAP
{
    vector<int>G[maxn];
    vector<Edge>edge;
    int s,t;
    int d[maxn];
    int cur[maxn];
    int p[maxn];
    int num[maxn];
    int flow;
    void init()
    {
        for(int i=0;i<=n+m+1;i++)
            G[i].clear();
        s=0;
        t=n+m+1;
    }
    bool bfs()
    {
        memset(d,-1,sizeof(d));
        queue<int>q;
        q.push(t);
        d[t]=0;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=0;i<G[u].size();i++)
            {
                Edge& e=edge[G[u][i]];
                if(e.cap==0&&d[e.v]==-1)
                {
                    d[e.v]=d[u]+1;
					q.push(e.v);
                }
            }
        }
        return d[s]!=-1;
    }
    int Augment()
    {
        int x=t,a=inf;
        while(x!=s)
        {
            Edge& e=edge[p[x]];
            a=min(a,e.cap-e.flow);
            x=edge[p[x]].u;
        }
        x=t;
        while(x!=s)
        {
            edge[p[x]].flow+=a;
            edge[p[x]^1].flow-=a;
            x=edge[p[x]].u;
        }
        return a;
    }
    int maxflow(int s,int t)
    {
        this->s=s;
        this->t=t;
        flow=0;
        bfs();
        for(int i=0;i<=n+m+1;i++)
            num[d[i]]++;
        int x=s;
        memset(cur,0,sizeof(cur));
        while(d[s]<n+m+2)
        {
            if(x==t)
            {
                flow+=Augment();
                x=s;
            }
            bool ok=false;
            for(int i=cur[x];i<G[x].size();i++)
            {
                Edge& e=edge[G[x][i]];
                if(e.cap>e.flow&&d[x]==d[e.v]+1)
                {
                    ok=true;
                    p[e.v]=G[x][i];
                    cur[x]=i;
                    x=e.v;
                    break;
                }
            }
            if(!ok)
            {
                int k=n+m+1;
                for(int i=0;i<G[x].size();i++)
                {
                    Edge& e=edge[G[x][i]];
                    if(e.cap>e.flow)
                        k=min(k,d[e.v]);
                }
                if(--num[d[x]]==0)
                    break;
                num[d[x]=k+1]++;
                cur[x]=0;
                if(x!=s)
                    x=edge[p[x]].u;
            }
        }
        return flow;
    }
}solver;
char buffer[11000];
void add(int s,int t,int cap)
{
    edge.push_back(Edge(s,t,0,cap));
    edge.push_back(Edge(t,s,0,0));
    int x=edge.size();
    solver.G[s].push_back(x-2);
    solver.G[t].push_back(x-1);
}
void input()
{
    solver.init();
    int x;
    edge.clear();
    char ch[100];
    for (int i = 1 ; i <= n ; ++i)
    {
		add(0,i,1);
		scanf("%*s");
		gets(buffer);
		char * p = strtok(buffer, " ");
		while (p) {
			sscanf(p,"%d",&x);
			add(i,x+1+n,1);
			p = strtok(NULL," ");
		}
	}
    int sz=edge.size();
    for(int i=n+1;i<=n+m;i++)
    {
        sz+=2;
        solver.G[i].push_back(sz-2);
        solver.G[n+m+1].push_back(sz-1);
    }
}
void build(int up)
{
    solver.edge=edge;
    for(int i=n+1;i<=n+m;i++)
    {
        solver.edge.push_back(Edge(i,n+m+1,0,up));
		solver.edge.push_back(Edge(n+m+1,i,0,0));
    }
}
void solve()
{
    int left=1,right=n;
    int mid=(left+right)>>1;
    int ans=n;
    while(left<=right)
    {
        build(mid);
        if (solver.maxflow(0,n+m+1)==n)
        {
			right = mid-1;
			ans = min(ans,mid);
		}
		else
        {
			left = mid+1;
		}
		mid = (left+right)>>1;
    }
    printf("%d\n",ans);
}
int main()
{
	while(scanf("%d%d",&n,&m)==2,n+m)
	{
		input();
		solve();
	}
}

UVA 1345 Jamie's Contact Groups

时间: 2024-09-29 22:09:18

UVA 1345 Jamie's Contact Groups的相关文章

UVA 1345 - Jamie&#39;s Contact Groups(二分+最大流)

UVA 1345 - Jamie's Contact Groups 题目链接 题意:给定一些人,每个人有一个分组,现在要每个人选一个分组,使得所有分组中最大的人数最小,问这个最小值是多少 思路:二分答案,然后利用最大流去判定,源点往每个人建一条边容量为1,每个人往各自的分组建一条边,容量为1,分组向汇点建一条边,容量为二分出来的值,这样跑一下最大流如果最大流等于n,就是能满足 代码: #include <cstdio> #include <cstring> #include <

uva 1345 Jamie&#39;s Contact Groups (最大流+二分)

uva 1345 Jamie's Contact Groups Description Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long contact list in her cell phone. The contact list has become so long that it often takes a long time for her to br

UValive3268 Jamie&#39;s Contact Groups(二分+最大流)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1269 Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very long contact list in her cell phone. The c

UVALive-3268 Jamie&#39;s Contact Groups (最大流,网络流建模)

题目大意:你的手机通讯录里有n个联系人,m个分组,其中,有的联系人在多个分组里.你的任务是在一些分组里删除一些联系人,使得每个联系人只在一个分组里并且使人数最多的那个分组人数最少.找出人数最多的那个分组中的人数. 题目分析:要求的是最小的最大值,二分枚举这个最小的最大人数x.增加源点s和汇点t,从s向每一个联系人连一条弧,容量为1,表示一个联系人只能在一个分组中:然后对于每个联系人向他所在的分组连一条弧,容量为1,表示在这个分组里最多保存一次该联系人:然后从每个分组向汇点连一条弧,容量为x,表示

POJ 2289 Jamie&#39;s Contact Groups 二分图多重匹配

题意:n个人,m个组,给出每个人可以分到那些组中,把每个人都分进某组中,问最大组的人数最小为?n<=1e3,m<=500,二分图多重匹配 左边为人 右边为分组 可以多个人对一个组由于要求最大组的最小人数 二分答案x,右边点最多流量为x,判断匹配数是否n即可. #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; t

Poj 2289 Jamie&#39;s Contact Groups (二分+二分图多重匹配)

题目链接: Poj 2289 Jamie's Contact Groups 题目描述: 给出n个人的名单和每个人可以被分到的组,问将n个人分到m个组内,并且人数最多的组人数要尽量少,问人数最多的组有多少人? 解题思路: 二分图多重匹配相对于二分匹配来说不再是节点间的一一对应,而是Xi可以对应多个Yi.所以我们就需要一个限制(Xi最多匹配几个Yi).当Yi需要匹配Xi的时候,Xi的匹配未到上限,直接匹配,否则进行增广路.其实是二分图多重匹配的模板题,再套一个二分枚举最多组的人数就OK咯.下面就上板

POJ2289 Jamie&#39;s Contact Groups(二分图多重匹配)

题意: 给定一个规模为n的名单,要将名单中的人归到m个组中,给出每个人可能的分组号,需要确定一种分配方案,使得最大规模的组最小. 思路: 二分图多重匹配 如果所到的组没满,就去那个组 如果满了,就从那个组里踢出一个 如果能踢出来,就把那个踢出来,把当前的放进去 如果所有能到的组都踢不出来,就不对了 至于那个最大规模的具体值,二分一下就OK了 /* *********************************************** Author :devil Created Time

Jamie&#39;s Contact Groups

poj2289:http://poj.org/problem?id=2289 题意:给定一个规模为n的名单,要将名单中的人归到m个组中,给出每个人可能的分组号,需要确定一种分配方案,是的最大规模的组最小. 题解:很明显的二分.然后把人和组都拆点即可. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #include<queue>

POJ 2289 Jamie&#39;s Contact Groups (二分+最大流)

题目大意: 有n个人,可以分成m个组,现在给出你每个人可以去的组的编号,求分成的m组中人数最多的组最少可以有多少人. 算法讨论: 首先喷一下这题的输入,太恶心了. 然后说算法:最多的最少,二分的字眼.二分什么,因为我们说的是组的人,所以要对组的流出量进行二分.其余的都连流量为1的边,然后对“小组”点的流出量二分连边,最后跑最大流判断 是否等于N即可.还是蛮简单的. Codes: 1 #include <cstdio> 2 #include <cstring> 3 #include