SCU3312 Stockholm Knights(最大流)
2016-03-22 21:18
344 查看
题目大概说一个n×m的格子中,'.'代表空地,'#'代表障碍,'K'代表骑士,'D'代表目的地。骑士每走一步花一条,每一步可以往(+2,+3)(-2,+3)...八个方向走,问占领所有目的地最少要几天。
二分枚举天数用最大流判定能否成立——建图关键在于把每一个格子点拆成天数个的点,因为每个格子每天只能容纳一个骑士所以各个天的点再拆成两个点之间连容量1的边,然后就是对所有第i天的点向所有第i+1天的点连容量1的边。
二分枚举天数用最大流判定能否成立——建图关键在于把每一个格子点拆成天数个的点,因为每个格子每天只能容纳一个骑士所以各个天的点再拆成两个点之间连容量1的边,然后就是对所有第i天的点向所有第i+1天的点连容量1的边。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 66666 #define MAXM 888888 struct Edge{ int v,cap,flow,next; }edge[MAXM]; int vs,vt,NV,NE,head[MAXN]; void addEdge(int u,int v,int cap){ edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0; edge[NE].next=head[u]; head[u]=NE++; edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0; edge[NE].next=head[v]; head[v]=NE++; } int level[MAXN]; int gap[MAXN]; void bfs(){ memset(level,-1,sizeof(level)); memset(gap,0,sizeof(gap)); level[vt]=0; gap[level[vt]]++; queue<int> que; que.push(vt); while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(level[v]!=-1) continue; level[v]=level[u]+1; gap[level[v]]++; que.push(v); } } } int pre[MAXN]; int cur[MAXN]; int ISAP(){ bfs(); memset(pre,-1,sizeof(pre)); memcpy(cur,head,sizeof(head)); int u=pre[vs]=vs,flow=0,aug=INF; gap[0]=NV; while(level[vs]<NV){ bool flag=false; for(int &i=cur[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){ flag=true; pre[v]=u; u=v; aug=min(aug,edge[i].cap-edge[i].flow); if(v==vt){ flow+=aug; for(u=pre[v]; v!=vs; v=u,u=pre[u]){ edge[cur[u]].flow+=aug; edge[cur[u]^1].flow-=aug; } aug=INF; } break; } } if(flag) continue; int minlevel=NV; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(edge[i].cap!=edge[i].flow && level[v]<minlevel){ minlevel=level[v]; cur[u]=i; } } if(--gap[level[u]]==0) break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return flow; } int dx[]={2,2,-2,-2,3,-3,3,-3}; int dy[]={3,-3,3,-3,2,2,-2,-2}; char map[33][33]; int n,m,tot; bool isok(int day){ vs=30*30*31*2; vt=vs+1; NV=vt+1; NE=0; memset(head,-1,sizeof(head)); for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ if(map[i][j]=='#') continue; if(map[i][j]=='K') addEdge(vs,i*m+j,1); else if(map[i][j]=='D') addEdge(i*m+j+n*m*day+27000,vt,1); for(int t=0; t<=day; ++t){ addEdge(i*m+j+n*m*t,i*m+j+n*m*t+27000,1); if(t==day) continue; addEdge(i*m+j+n*m*t+27000,i*m+j+n*m*(t+1),1); for(int k=0; k<8; ++k){ int nx=i+dx[k],ny=j+dy[k]; if(nx<0 || nx>=n || ny<0 || ny>=m || map[nx][ny]=='#') continue; addEdge(i*m+j+n*m*t+27000,nx*m+ny+n*m*(t+1),1); } } } } return ISAP()==tot; } int main(){ int t; scanf("%d",&t); while(t--){ tot=0; scanf("%d%d",&n,&m); for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ scanf(" %c",&map[i][j]); if(map[i][j]=='D') ++tot; } } if(tot==0){ puts("0"); continue; } int l=0,r=31; while(l<r){ int mid=l+r>>1; if(isok(mid)) r=mid; else l=mid+1; } if(l>30) puts(">30"); else printf("%d\n",l); } return 0; }
相关文章推荐
- oracle 转 mysql 最新有效法(转)
- linux grep命令详解(转)
- 【译】Swift 字符串速查表
- 作业4:结对项目—— 词频统计
- spring AOP 两种底层实现( JDK动态代理 和 CGLIB代理)
- 猜数字
- 猜数字
- 查找与排序之冒泡排序篇(C语言实现)
- PAT (Advanced Level) Practise 1070 Mooncake (25)
- 贪心算法(下)
- IOS学习之websocket使用方法
- OpenStack自动化部署----单节点的自动安装(DevStack(含apt-get更换源))
- Java --- 异常处理和设计
- IT小小鸟读后感
- Js数组组合输出
- 关于人之理解
- python 中*args和**kw详解
- 一道看似很简单的题目,竟然让很多人丢了分
- java中>,>>,>>> 的区别
- linux sed命令详解(转)