题目根本粘贴不上,口述一波。
题目大意:有一天警察去一个酒吧去抓机器人,酒吧的老板说他这里只有两种人,没有机器人,这两种人的特点是,第一种人会在酒吧呆至少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");
}
}
}