题目
神犇ddddddpppppp勤奋好学,经常会找Fanvree大神问问题。
终于有一天,Fanvree忍无可忍(因为dp问的问题在他看来太无聊),他决定躲在某个机房让dp无法找到他。
所有的机房在一个二维平面上,可以视为一个网格图,每个网格就代表一个机房或者是杂物房。
为了不被dp发现,Fanvree找来了小伙伴帮助他。其中有A个男生,B个女生,和小标。如果每一个男生都有一个女生和他在同一个机房,且每一个女生都有一个男生和她在同一个机房,那么dp就不能找到Fanvree。由于小标CJ资料上填写的是”decline to aswer”,所以她既能和男生一对,也能和女生一对。需要注意的是:最终每一个机房最多只能有一对人,而且小标也一定要配对。每个人可以同时在四相邻的机房间移动(不能移动到杂物房),因此只要一男一女在同一个机房,他们就算是一对了。
现在Fanvree知道每一个人初始的位置和移动速度(即移动到相邻机房所需要的时间,下同)。请你帮Fanvree计算一下,在使得所有人都有人和他(她)配对的情况下,最后完成配对的时间最少是多少。
第一行,四个整数N,M,A,B,分别表示网格图大小,男生数量和女生数量。
接下来N行M列,每个位置是’.’或’#’,’.’表示机房,’#’表示杂物房。
接下来一行,三个正整数XA,YA,TA,表示小标的初始位置和移动速度。
接下来A行,每行三个正整数Xi,Yi,Ti,表示第i个男生的初始位置和移动速度。
接下来B行,每行三个正整数Xj,Yj,Tj,表示第j个女生的初始位置和移动速度。
N,M<=22, A,B<=N*M
分析
初初看到题目我是一脸懵逼。
首先小标就是唬人的,直接把他归成人少那一边。然后干什么?分配每个人到哪个房间里?明显超时。一男一女···最大匹配?题目给的是移动一格的时间,也不知道男女跑到哪个格子。
重新看题目,发现输出的是答案,那我们可以想想二分。二分最长那个人的移动距离?消耗时间?都行。
这之后我们再往之前的思路想,就发现网络流可行了。左边一排男生和S连,中间一排机房,右边一排女生和T连。注意机房拆点。然后随便跑跑~~~注意优化一下时间复杂度或者常数,因为22*22很悬。
所以说:
1,直接输出的是答案,可以往二分想;
2,根本没有分配策略的时候,想网络流吧。
代码
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
typedef long long ll;
const ll mx=1000000007;
const int N=500000;
const int fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll te[1000],dis[1000][1000],l,r,mid;
int now[N*2],ttt,di[N*2],cnt,pdd[N*2],b[N*4],c[N*4],next[N*4],rev[N*4],first[N*2],tt,s,t,i,j,n,m,t1,t2,x[1000],y[1000],q1,q2,d[1000][3],nx,ny,pd[25][25],a[25][25],ans,mn;
void bfs()
{
fo(i,1,t1+t2)
{
dis[i][x[i]*m-m+y[i]]=0;
q1=0;q2=1;d[1][1]=x[i];d[1][2]=y[i];pd[x[i]][y[i]]=i;
while (q1<q2)
{
q1++;
fo(j,0,3)
{
nx=d[q1][1]+fx[j][0];
ny=d[q1][2]+fx[j][1];
if (a[nx][ny]=='.'&&pd[nx][ny]!=i)
{
dis[i][nx*m-m+ny]=dis[i][d[q1][1]*m-m+d[q1][2]]+1;
d[++q2][1]=nx;
d[q2][2]=ny;
pd[nx][ny]=i;
}
}
}
}
}
void cr(int x,int y,int z,int t)
{
tt++;
b[tt]=y;
c[tt]=t;
rev[tt]=tt+z;
next[tt]=first[x];
first[x]=tt;
}
void make()
{
fo(i,1,tt)
b[i]=c[i]=rev[i]=next[i]=0;
fo(i,s,t) first[i]=di[i]=0;
tt=0;
fo(i,1,t1)
{
cr(s,i,1,1),
cr(i,s,-1,0);
fo(j,1,n*m)
if (dis[i][j]<=mid/te[i])
{
cr(i,j+t1+t2,1,1);
cr(j+t1+t2,i,-1,0);
}
}
fo(i,1,t2)
{
cr(t1+i,t,1,1);
cr(t,t1+i,-1,0);
fo(j,1,n*m)
if (dis[i+t1][j]<=mid/te[i+t1])
{
cr(j+t1+t2+n*m,i+t1,1,1);
cr(i+t1,j+t1+t2+n*m,-1,0);
}
}
fo(i,1,n*m)
cr(i+t1+t2,i+t1+t2+n*m,1,1),
cr(i+t1+t2+n*m,i+t1+t2,-1,0);
}
ll maxflow(int x,int y)
{
pdd[x]=ttt;
if (x==t)
{
ans+=y;
return y;
}
for(int p=now[x];p;p=next[p])
if (c[p]&&pdd[b[p]]!=ttt&&di[x]==di[b[p]]+1)
{
int l=maxflow(b[p],min(c[p],y));
if (l)
{
now[x]=p;
c[p]-=l;
c[rev[p]]+=l;
return l;
}
}
now[x]=0;
return 0;
}
int change()
{
mn=mx;
fo(i,s,t)
if (pdd[i]==ttt)
{
for(int p=first[i];p;p=next[p])
if (pdd[b[p]]!=ttt&&c[p])
mn=min(mn,di[b[p]]+1-di[i]);
}
if (mn==mx) return 0;
fo(i,s,t)
if (pdd[i]==ttt)
di[i]+=mn;
return 1;
}
int main()
{
freopen("hide.in","r",stdin);
scanf("%d%d%d%d\n",&n,&m,&t1,&t2);
fo(i,1,n)
{
fo(j,1,m)
{
scanf("%c",&a[i][j]);
if (a[i][j]=='.') cnt++;
}
scanf("\n");
}
s=0;
t=t1+t2+n*m*2+2;
fo(i,1,t1+t2) fo(j,1,n*m) dis[i][j]=mx*n*m;
scanf("%d%d%d",&l,&r,&mid);
fo(i,1,t1) scanf("%d%d%lld",x+i,y+i,te+i);
if (t1<t2)
t1++,x[t1]=l,y[t1]=r,te[t1]=mid;
fo(i,1,t2) scanf("%d%d%d",x+i+t1,y+i+t1,te+i+t1);
if (t1>t2)
t2++,x[t1+t2]=l,y[t1+t2]=r,te[t1+t2]=mid;
if (t1!=t2)
{
printf("-1");
return 0;
}
bfs();
l=0;
r=cnt*mx;
while (l<r)
{
mid=(l+r)/2;
make();
ans=0;
do
{
fo(i,s,t) now[i]=first[i];
ttt++;
while (maxflow(0,mx))
ttt++;
}while(change());
if (ans==t1) r=mid;
else l=mid+1;
}
if (r==cnt*mx) r=-1;
printf("%lld",r);
}