【GDOI2017模拟8.12】躲藏
2016-08-13 16:49
309 查看
Description
给出一个n*m的网格图,图中有一些障碍节点。现在有A个男生和B个女生,还有一个小标。
男生要和女生配对,小标可以和任何一个人配对。
每一对CP(雾)只能待在一个点。一个点只能有一对CP。
现在给出A+B+1个人的初始坐标,和他们的移动速度(即移动到4相邻格子所需的时间)
所有人同时移动,求完成配对的最小时间。
Solution
首先,小标的性别完全可以确定,不用管。然后,我们发现我们要让最长的移动时间最小。
二分答案,判定显然用网络流。
如何建模?
首先,因为每个男生和每个女生都要在一个点,我们不妨把这个点放在中间,左边男生连它,右边女生连他。这里如果有边相连就表示这个人能够在二分上界中到达这个点。
每个点拆点,自己连1.表示这里只能有一对CP。
然后跑最大流就是最多能匹配的CP数,判断一下就好了。
Code
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define rep(i,a) for(int i=last[a];i;i=next[i]) #define L 505 #define N 2005 #define M 810005 using namespace std; typedef long long ll; const ll inf=1e13; struct note{int x,y;ll t;}a[L],b[L],q ; int n,m,A,B,S,T,l,x,y,dis ,d ; ll dist[L*2][L],time; int last ,next[M],t[M],f[M],g[4][2]={0,1,1,0,0,-1,-1,0}; char s[L][L]; void add(int x,int y,int z) { t[++l]=y;f[l]=z;next[l]=last[x];last[x]=l; t[++l]=x;f[l]=0;next[l]=last[y];last[y]=l; } int get(int x,int y) {return (x-1)*m+y;} bool bfs() { memset(dis,0,sizeof(dis));dis[S]=1; int i=0,j=1;d[1]=S; while (i<j) rep(k,d[++i]) if (!dis[t[k]]&&f[k]) dis[t[k]]=dis[d[i]]+1,d[++j]=t[k]; return dis[T]; } int dinic(int x,int y) { if (x==T) return y; int now=0; rep(i,x) if (dis[t[i]]==dis[x]+1&&f[i]) { int k=dinic(t[i],min(y,f[i])); f[i]-=k;f[i^1]+=k;y-=k;now+=k; if (!y) break; } if (!now) dis[x]=-1; return now; } bool check(ll x) { memset(last,0,sizeof(last));l=1;int ans=0; fo(i,1,A) add(S,i,1);fo(i,1,B) add(i+A+2*n*m,T,1); fo(i,1,A) fo(j,1,n*m) if (dist[i][j]<=x) add(i,j+A,1); fo(i,1,B) fo(j,1,n*m) if (dist[i+A][j]<=x) add(j+A+n*m,i+A+2*n*m,1); fo(i,1,n*m) add(i+A,i+A+n*m,1); while (bfs()) ans+=dinic(S,0x7fffffff); if (ans==A) return 1;else return 0; } void len(int v,int x,int y,ll t) { dist[v][get(x,y)]=0; int i=0,j=1;q[1].x=x;q[1].y=y; while (i<j) { x=q[++i].x,y=q[i].y; fo(k,0,3) { int xx=x+g[k][0],yy=y+g[k][1],zz=get(xx,yy); if (xx<1||xx>n||yy<1||yy>m||s[xx][yy]=='#'||dist[v][zz]!=dist[0][0]) continue; q[++j].x=xx;q[j].y=yy;q[j].t=q[i].t+t;dist[v][zz]=q[j].t; } } } int main() { scanf("%d%d%d%d",&n,&m,&A,&B);S=0;T=A+B+2*n*m+2; if (A==B||abs(A-B)>1) {printf("-1");return 0;} fo(i,1,n) scanf("%s",s[i]+1); scanf("%d%d%lld",&x,&y,&time);memset(dist,127,sizeof(dist)); fo(i,1,A) scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].t); fo(i,1,B) scanf("%d%d%lld",&b[i].x,&b[i].y,&b[i].t); if (A<B) a[++A].x=x,a[A].y=y,a[A].t=time; else b[++B].x=x,b[B].y=y,b[B].t=time; fo(i,1,A) len(i,a[i].x,a[i].y,a[i].t); fo(i,1,B) len(i+A,b[i].x,b[i].y,b[i].t); ll le=1,ri=inf; while (le<ri) { ll mid=(le+ri)/2; if (check(mid)) ri=mid;else le=mid+1; } if (le==inf) printf("-1");else printf("%lld",le); }
相关文章推荐
- 【GDOI2017模拟8.12】新车
- 【GDOI2017模拟8.12】字符串
- JZOJ4858. 【GDOI2017模拟11.4】Walk
- 【GDOI2017模拟11.2】相位幻击
- JZOJ4843. 【GDOI2017模拟11.2】相位幻击
- 【GDOI2017模拟12.3】告别
- 【GDOI2017模拟8.14】佐助的难题
- JZOJ4769 【GDOI2017模拟9.9】graph CDQ分治+用按秩合并维护带撤销的并查集(BZOJ 4025)
- JZOJ4779. 【GDOI2017模拟9.14】鞍点
- jzoj【GDOI2017第二轮模拟day2】开房间
- 【GDOI2017第二轮模拟day2】中位数
- 【GDOI2017第三轮模拟day1】影魔(主席树)
- 【GDOI2017模拟10.30】分组
- 【GDOI2017模拟9.9】[IOI2007]偶环
- 【GDOI2017模拟8.11】总结
- 【jzoj5322】【GDOI2017模拟8.21】【小朋友】【状态压缩动态规划】
- 4774. 【GDOI2017模拟9.10】子串
- 【GDOI2017第二轮模拟day1】公路建设(克鲁斯卡尔最小生成树+线段树+归并)
- 【GDOI2017第二轮模拟day1】公路建设
- JZOJ4844. 【GDOI2017模拟11.2】抗拒黄泉 背包合并相同状态优化容斥