UVALive - 3231,二分&最大流

Fair Share

You are given N processors and M jobs to be processed. Two processors are specified to each job.
To process the job, the job should be allocated to and executed on one of the two processors for one
unit of time. If K jobs are allocated to a processor, then it takes K units of time for the processor
to complete the jobs. To complete all the jobs as early as possible, you should allocate the M jobs to
the N processors as fair as possible. Precisely speaking, you should minimize the maximum number of
jobs allocated to each processor over all processors. The quantity, minimum number of jobs, is called
fair share.
For example, you are given 5 processors and 6 jobs. Each job can be allocated to one of the two
processors as shown in the table below. Job 1 can be allocated to processors 1 or 2, and job 2 can be
allocated to processors 2 or 3, etc. If you allocate job 1 to processor 1, job 2 to processor 2, job 3 to
processor 3, job 4 to processor 4, job 5 to processor 5, and job 6 to processor 1, then you have at most
two jobs allocated to each processor. Since there are more jobs than processors in this example, some
processors necessarily have at least two jobs, and thus the fair share is two.

题意:有n个人,m份工作,第i份工作只能由ai或者bi这两个人之一完成,设n个人中工作最多的那个人有x份工作,现让你最小化x值
思路:首先二分答案,当工作最多的那个人有mid份工作时,将每个人拆成左右两个点,左侧向右侧连一条容量为mid的边,即这个人最多只能由mid份工作,然后由源点向每份工作连一条容量为1的边,每份工作又向对应的两个完成人的左部点连容量为1的边,可保证一份工作只会被完成一次,每个人的右部点向汇点连一条容量为1的边,跑最大流,如果最大流为m即表示m份工作都能被完成,答案还能更小

#include<bits/stdc++.h>
#define MAXN 11010
#define MAXM 31010
using namespace std;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct edge
{
    int v,c,nxt;
}edg[MAXM << 1];
inline void addedg(int u,int v,int c)
{
    edg[tot].v = v;
    edg[tot].c = c;
    edg[tot].nxt = head[u];
    head[u] = tot++;
}
inline void add(int u,int v,int c)
{
    addedg(u,v,c);
    addedg(v,u,0);
}
int n,m,d[MAXN];
inline bool bfs(int s,int t)
{
    queue<int> qu;
    memset(d,-1,sizeof(int)*(m+n+2));
    qu.push(s);
    d[s] = 0;
    int v;
    while(!qu.empty())
    {
        int u = qu.front();
        qu.pop();
        for(int i = head[u];i != -1;i = edg[i].nxt)
        {
            v = edg[i].v;
            if(edg[i].c > 0 && d[v] == -1)
                d[v] = d[u]+1,qu.push(v);
        }
    }
    return d[t] != -1;
}
int dfs(int u,int flow,int t)
{
    if(u == t)
        return flow;
    int res = 0;
    for(int i = head[u];i != -1;i = edg[i].nxt)
    {
        int v = edg[i].v;
        if(edg[i].c > 0 && d[v] == d[u] + 1)
        {
            int tmp = dfs(v,min(flow,edg[i].c),t);
            flow -= tmp;
            res += tmp;
            edg[i].c -= tmp;
            edg[i^1].c += tmp;
            if(flow == 0)
                break;
        }
    }
    if(res == 0)
        d[u] = -1;
    return res;
}
inline void init()
{
    memset(head,-1,sizeof(int)*(m+n+2));
    tot = 0;
}
int fcnt,ecnt;
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d",&n,&m);
        init();
        int s,t,u,v;
        s = 0,t = m+n+1;
        for(int i = 1;i <= m;++i)
        {
            add(s,i,1);
            scanf("%d%d",&u,&v);
            add(i,m+u,1),add(i,m+v,1);
        }
        bool flag = false;
        int l = 0,r = m,mid,ans;
        while(l <= r)
        {
            mid = (l+r) >> 1;
            if(!flag)
            {
                fcnt = tot;
                for(int i = m+1;i <= m+n;++i)
                    add(i,t,mid);
                ecnt = tot;
                flag = true;
//                for(int u = s;u <= t;++u)
//                {
//                    for(int i = head[u];i != -1;i = edg[i].nxt)
//                        if(!(i & 1))
//                            printf("%d %d %d\n",u,edg[i].v,edg[i].c);
//                }
            }
            else
            {
                for(int i = 0;i < fcnt;i += 2)
                    edg[i].c = 1,edg[i^1].c = 0;
                for(int i = fcnt;i < ecnt;i += 2)
                    edg[i].c = mid,edg[i^1].c = 0;
                for(int i = ecnt;i < tot;i += 2)
                    edg[i].c = 1,edg[i^1].c = 0;
            }
            int res = 0;
            while(bfs(s,t))
                res += dfs(s,INF,t);
            if(res == m)
            {
                ans = mid;
                r = mid-1;
            }
            else
                l = mid+1;
        }
       printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值