Those are not the droids you're looking for Gym - 100285H 二分图 最大流

题目根本粘贴不上,口述一波。

题目大意:有一天警察去一个酒吧去抓机器人,酒吧的老板说他这里只有两种人,没有机器人,这两种人的特点是,第一种人会在酒吧呆至少A个小时,另一种人会在网吧最多呆B个小时。现在给你酒吧门的进出记录,让酒吧老板自圆其说,如果不能自圆其说就说明老板是个骗子,否则就输出详细的人物进入与离开的时间。

首先想到二分匹配,大概做法就是建图+最大流。

方法:设超级起点s,超级终点f。s与每一个进入点连线,每一个出点与f连线,容量均为1.然后遍历所有入点与出点,如果可以链接那么就链接,容量也为1.

紧接着跑一个最大流就Ok,还有要记录一下节点。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
const int M=1e3+10;
struct aa
{
    int u,v,r,next;
} edge[1666666];
int dis[M],pre[M],head[M],s,f,cnt,cnt1,cnt2,n,s1[M],s2[M],a,b;
int mach[M];
void add(int u,int v,int r)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].r=r;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].r=0;
    edge[cnt].next=pre[v];
    pre[v]=cnt++;
}
bool bfs()
{
    memset(dis,-1,sizeof(dis));
    queue<int>que;
    dis[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=pre[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            int r=edge[i].r;
            if(dis[v]==-1&&r)
            {
                dis[v]=dis[u]+1;
                que.push(v);
            }
        }
    }
    return dis[f]>=0;
}
int dfs(int now,int Min)
{
    int T,flow=0;
    if(now==f)
        return Min;
    for(int &i=head[now]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        int r=edge[i].r;
        if(dis[v]==dis[now]+1&&r&&(T=dfs(v,min(Min-flow,r))))
        {
            edge[i].r-=T;
            edge[i^1].r+=T;
            mach[now]=v;
            flow+=T;
            if(flow==Min)
                break;
        }
    }
    return flow;

}
int MAX_flow()
{
    int sum=0;
    int cont=1;
    while(bfs())
    {
        for(int i=0; i<=n+1; i++)
            head[i]=pre[i];
        while(int temp=dfs(s,0x3f3f3f3f))
            sum+=temp;
    }
    return sum;
}
int main()
{
    while(scanf("%d%d",&a,&b)!=EOF)
    {
        scanf("%d",&n);
        cnt=0,cnt1=1;
        cnt2=1;
        memset(pre,-1,sizeof(pre));
        memset(mach,0,sizeof(mach));
        s=0,f=n+1;
        for(int i=0; i<n; i++)
        {
            int t,p;
            scanf("%d%d",&t,&p);
            if(p==1)
            {
                s2[cnt2++]=t;
            }
            else
            {
                s1[cnt1++]=t;
            }
        }
        for(int i=1; i<cnt1; i++)
        {
            add(s,i,1);
            add(n/2+i,f,1);
            for(int j=1; j<cnt2; j++)
            {
                if(s2[j]-s1[i]>=a||s2[j]-s1[i]<=b)
                {
                    add(i,n/2+j,1);
                }
            }
        }
        int ans=MAX_flow();
        if(ans==n/2)
        {
            printf("No reason\n");
            for(int i=1; i<=n/2; i++)
            {
                if(mach[i])
                    printf("%d %d\n",s1[i],s2[mach[i]-n/2]);
            }
        }
        else
        {
            printf("Liar\n");
        }

    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值