SCU3312 Stockholm Knights(最大流)
题目大概说一个n×m的格子中,'.'代表空地,'#'代表障碍,'K'代表骑士,'D'代表目的地。骑士每走一步花一条,每一步可以往(+2,+3)(-2,+3)...八个方向走,问占领所有目的地最少要几天。
二分枚举天数用最大流判定能否成立——建图关键在于把每一个格子点拆成天数个的点,因为每个格子每天只能容纳一个骑士所以各个天的点再拆成两个点之间连容量1的边,然后就是对所有第i天的点向所有第i+1天的点连容量1的边。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 66666 8 #define MAXM 888888 9 struct Edge{ 10 int v,cap,flow,next; 11 }edge[MAXM]; 12 int vs,vt,NV,NE,head[MAXN]; 13 void addEdge(int u,int v,int cap){ 14 edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0; 15 edge[NE].next=head[u]; head[u]=NE++; 16 edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0; 17 edge[NE].next=head[v]; head[v]=NE++; 18 } 19 int level[MAXN]; 20 int gap[MAXN]; 21 void bfs(){ 22 memset(level,-1,sizeof(level)); 23 memset(gap,0,sizeof(gap)); 24 level[vt]=0; 25 gap[level[vt]]++; 26 queue<int> que; 27 que.push(vt); 28 while(!que.empty()){ 29 int u=que.front(); que.pop(); 30 for(int i=head[u]; i!=-1; i=edge[i].next){ 31 int v=edge[i].v; 32 if(level[v]!=-1) continue; 33 level[v]=level[u]+1; 34 gap[level[v]]++; 35 que.push(v); 36 } 37 } 38 } 39 int pre[MAXN]; 40 int cur[MAXN]; 41 int ISAP(){ 42 bfs(); 43 memset(pre,-1,sizeof(pre)); 44 memcpy(cur,head,sizeof(head)); 45 int u=pre[vs]=vs,flow=0,aug=INF; 46 gap[0]=NV; 47 while(level[vs]<NV){ 48 bool flag=false; 49 for(int &i=cur[u]; i!=-1; i=edge[i].next){ 50 int v=edge[i].v; 51 if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){ 52 flag=true; 53 pre[v]=u; 54 u=v; 55 aug=min(aug,edge[i].cap-edge[i].flow); 56 if(v==vt){ 57 flow+=aug; 58 for(u=pre[v]; v!=vs; v=u,u=pre[u]){ 59 edge[cur[u]].flow+=aug; 60 edge[cur[u]^1].flow-=aug; 61 } 62 aug=INF; 63 } 64 break; 65 } 66 } 67 if(flag) continue; 68 int minlevel=NV; 69 for(int i=head[u]; i!=-1; i=edge[i].next){ 70 int v=edge[i].v; 71 if(edge[i].cap!=edge[i].flow && level[v]<minlevel){ 72 minlevel=level[v]; 73 cur[u]=i; 74 } 75 } 76 if(--gap[level[u]]==0) break; 77 level[u]=minlevel+1; 78 gap[level[u]]++; 79 u=pre[u]; 80 } 81 return flow; 82 } 83 int dx[]={2,2,-2,-2,3,-3,3,-3}; 84 int dy[]={3,-3,3,-3,2,2,-2,-2}; 85 char map[33][33]; 86 int n,m,tot; 87 bool isok(int day){ 88 vs=30*30*31*2; vt=vs+1; NV=vt+1; NE=0; 89 memset(head,-1,sizeof(head)); 90 for(int i=0; i<n; ++i){ 91 for(int j=0; j<m; ++j){ 92 if(map[i][j]=='#') continue; 93 if(map[i][j]=='K') addEdge(vs,i*m+j,1); 94 else if(map[i][j]=='D') addEdge(i*m+j+n*m*day+27000,vt,1); 95 for(int t=0; t<=day; ++t){ 96 addEdge(i*m+j+n*m*t,i*m+j+n*m*t+27000,1); 97 if(t==day) continue; 98 addEdge(i*m+j+n*m*t+27000,i*m+j+n*m*(t+1),1); 99 for(int k=0; k<8; ++k){ 100 int nx=i+dx[k],ny=j+dy[k]; 101 if(nx<0 || nx>=n || ny<0 || ny>=m || map[nx][ny]=='#') continue; 102 addEdge(i*m+j+n*m*t+27000,nx*m+ny+n*m*(t+1),1); 103 } 104 } 105 } 106 } 107 return ISAP()==tot; 108 } 109 int main(){ 110 int t; 111 scanf("%d",&t); 112 while(t--){ 113 tot=0; 114 scanf("%d%d",&n,&m); 115 for(int i=0; i<n; ++i){ 116 for(int j=0; j<m; ++j){ 117 scanf(" %c",&map[i][j]); 118 if(map[i][j]=='D') ++tot; 119 } 120 } 121 if(tot==0){ 122 puts("0"); 123 continue; 124 } 125 int l=0,r=31; 126 while(l<r){ 127 int mid=l+r>>1; 128 if(isok(mid)) r=mid; 129 else l=mid+1; 130 } 131 if(l>30) puts(">30"); 132 else printf("%d\n",l); 133 } 134 return 0; 135 }