UVALive-3268 Jamie's Contact Groups (最大流,网络流建模)

题目大意:你的手机通讯录里有n个联系人,m个分组,其中,有的联系人在多个分组里。你的任务是在一些分组里删除一些联系人,使得每个联系人只在一个分组里并且使人数最多的那个分组人数最少。找出人数最多的那个分组中的人数。

题目分析:要求的是最小的最大值,二分枚举这个最小的最大人数x。增加源点s和汇点t,从s向每一个联系人连一条弧,容量为1,表示一个联系人只能在一个分组中;然后对于每个联系人向他所在的分组连一条弧,容量为1,表示在这个分组里最多保存一次该联系人;然后从每个分组向汇点连一条弧,容量为x,表示这个分组不能保存超过x个联系人。求最大流,如果源点s出发的每条边都满载,说明x可行。

代码如下:

# include<iostream>
# include<cstdio>
# include<cmath>
# include<string>
# include<vector>
# include<list>
# include<set>
# include<map>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

# define LL long long
# define REP(i,s,n) for(int i=s;i<n;++i)
# define CL(a,b) memset(a,b,sizeof(a))
# define CLL(a,b,n) fill(a,a+n,b)

const double inf=1e30;
const int INF=1<<30;
const int N=1505;

struct Edge
{
    int fr,to,cap,fw;
    Edge(int _fr,int _to,int _cap,int _fw):fr(_fr),to(_to),cap(_cap),fw(_fw){}
};
vector<Edge>edges,tedges;
vector<int>G[N];
int cur[N],vis[N],d[N],mark[505];

void init(int n)
{
    edges.clear();
    REP(i,0,n) G[i].clear();
}

void addEdge(int u,int v,int cap)
{
    edges.push_back(Edge(u,v,cap,0));
    edges.push_back(Edge(v,u,0,0));
    int m=edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}

bool BFS(int s,int t)
{
    CL(vis,0);
    vis[s]=1;
    d[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        REP(i,0,G[u].size()){
            Edge &e=edges[G[u][i]];
            if(!vis[e.to]&&e.cap>e.fw){
                d[e.to]=d[u]+1;
                vis[e.to]=1;
                q.push(e.to);
            }
        }
    }
    return vis[t];
}

int DFS(int u,int t,int a)
{
    if(u==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[u];i<G[u].size();++i){
        Edge &e=edges[G[u][i]];
        if(d[e.to]==d[u]+1&&(f=DFS(e.to,t,min(a,e.cap-e.fw)))>0){
            e.fw+=f;
            edges[G[u][i]^1].fw-=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}

int Dinic(int s,int t)
{
    int flow=0;
    while(BFS(s,t)){
        CL(cur,0);
        flow+=DFS(s,t,INF);
    }
    return flow;
}

bool read(int &x)
{
    x=0;
    char c;
    while(c=getchar()){
        if(c==‘ ‘) return true;
        else if(c==‘\n‘) return false;
        else x=x*10+c-‘0‘;
    }
}

bool judge()
{
    REP(i,0,G[0].size())
        if(edges[G[0][i]].cap>0&&edges[G[0][i]].cap!=edges[G[0][i]].fw) return false;
    return true;
}

int main()
{
    int n,m;
    char name[20];
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        init(n+m+2);
        CL(mark,0);
        REP(i,1,n+1){
            cin>>name;
            addEdge(0,m+i,1);
            int a;
            getchar();
            while(read(a)){
                ++mark[a];
                addEdge(m+i,a+1,1);
            }
            addEdge(m+i,a+1,1);
            ++mark[a];
        }

        int cnt=edges.size();
        tedges.clear();
        REP(i,0,cnt) tedges.push_back(edges[i]);

        int l=0,r=0;
        REP(i,0,m) r=max(r,mark[i]);
        while(l<r){
            int mid=l+(r-l)/2;
            init(n+m+2);
            REP(i,0,cnt) addEdge(tedges[i].fr,tedges[i].to,tedges[i].cap);
            REP(i,0,m) if(mark[i])
                addEdge(i+1,n+m+1,min(mid,mark[i]));
            Dinic(0,n+m+1);
            if(judge()) r=mid;
            else l=mid+1;
        }
        printf("%d\n",l);
    }
    return 0;
}

  

UVALive-3268 Jamie's Contact Groups (最大流,网络流建模)

时间: 2024-10-13 12:32:14

UVALive-3268 Jamie's Contact Groups (最大流,网络流建模)的相关文章

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

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

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

poj 2289 —— Jamie&#39;s Contact Groups 二分+最大流

原题:http://poj.org/problem?id=2289 #include<cstdio> #include<cstring> #include<string> #include<queue> #include<vector> #include<map> #include<algorithm> #define inf 1e9 using namespace std; const int maxn = 2000;

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

POJ2289 Jamie&#39;s Contact Groups —— 二分图多重匹配/最大流 + 二分

题目链接:https://vjudge.net/problem/POJ-2289 Jamie's Contact Groups Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 8147   Accepted: 2736 Description Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very lon

解题报告 之 POJ2289 Jamie&#39;s Contact Groups

解题报告 之 POJ2289 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

POJ 2289 Jamie&#39;s Contact Groups

二分答案+网络最大流 #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; int N,M; const int maxn = 2000 + 10; const int INF = 0x7FFFFFFF; struct Edge { int

UVA 1345 Jamie&#39;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