2547: [Ctsc2002]玩具兵
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 317 Solved: 152
[Submit][Status][Discuss]
Description
小明的爸爸给他买了一盒玩具兵,其中有 K个步兵,K个骑兵和一个天兵,个个高大威猛,形象逼真。盒子里还有一个M*N棋盘,每个格子(i,j)都有一个高度Hij,并且大得足以容纳所有的玩具兵。小明把所有的玩具兵都放到棋盘上去,突然想到了一种很有趣的玩法:任意挑选T个不同的格子,并给每个格子i规定一个重要值Ri--,游戏的目标就是每次沿东南西北之一的方向把一个玩具兵移动到其相邻的格子中(但不能移动到棋盘外面去),最终使得每个挑选出的格子i上恰好有Ri个玩具兵。小明希望所有的玩具兵都在某个选定的格子中,因此他总是使选出的T个格子的重要值之和等于玩具兵的个数。为了增加难度,小明给玩具兵们的移动方式做了一些规定:
- 步兵只会往高处爬,因此如果两个格子A和B相邻,当且仅当格子A的高度小于或等于B,步兵才可以从A移动到B。
- 骑兵只会往低处跳,因此如果两个格子A和B相邻,当且仅当格子A的高度大于或等于B,骑兵才可以从A移动到B。
- 天兵技术全面,移动不受任何限制。
可是没玩几次,小明就发现这个游戏太难了,他常常玩了好半天也达不到目的。于是,他设计了一种“超能力”,每使用一次超能力的时候,虽然不能移动任何一个玩具兵,但可对它们进行任意多次交换操作,每次交换两个玩具兵。等这次超能力使用完后又可和平常一样继续移动这些玩具兵。借助强大的超能力,这个游戏是容易玩通的,但是怎样才能让使用超能力的次数最少呢?
Input
第一行包含四个整数:M,N,K,T (2<=M,N<=100, 1<=K<=50, 1<=T<=2K+1)
第二行包括2K+1个数对(xi,yi),代表各个玩具兵的初始位置。前K个代表步兵,接下来的K个代表骑兵,最后一个代表天兵。
第三行包含T个三元组(xi,yi,ri),第i组代表第i个目标格的位置和重要值。
以下M行,每行N个整数。其中第i行第j个数为即格子的高度Hij。高度是不超过100的正整数,注意:不同玩具兵的初始位置可能相同。输入数据保证无错,选定的T个格子的重要值之和保证等于2K+1。
Output
仅包含一行,即使用超能力的最小次数T。
Solution
观察到每次交换可以换无数次,所以每次一定是把步兵和骑兵换一下,相当于每个都走到无路可走的地方,然后换个职业继续走。
所以对于每个玩具兵(先不考虑天兵),都处理出到每个点最少要交换的次数,也就是说,至少要交换 _dis[i][j] 次才能到达 (i,j)。
然后二分答案,二分出交换的次数 mid,然后对于每个玩具兵,向交换次数小于 mid 的终点连边,然后跑最大流即可。
注意最后要加上二分出的 mid,意义就是天兵每次都可以替代一个玩具兵走到终点,然后换它们俩就好。
Code
// By YoungNeal #include<queue> #include<cstdio> #include<cstring> int d[1000005]; int s,t,maxflow; int head[1000005]; int toy[1005][10]; int goal[1005][10]; int dis[1005][105]; // 记录交换了几次 dis[i][j]->第i个兵到第j个目标 int m,n,k,T,ans,cnt; int height[105][105]; int _dis[105][105][10]; // _dis[i][j]->从当前的点到(i,j)最少交换次数 bool in[105][105][5]; // in[i][j][p]->当前点到(i,j)职业为p是否在队列 int dx[]={-1,0,1,0},dy[]={0,1,0,-1}; struct Node{ int x,y,o; }; struct Edge{ int to,nxt,flow; }edge[10000005]; void add(int x,int y,int z){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; edge[cnt].flow=z; head[x]=cnt; } void spfa(int now,int xx,int yy,int cnt){ std::queue<Node> q; memset(in,0,sizeof in); memset(_dis,0x3f,sizeof _dis); _dis[xx][yy][cnt]=0; q.push((Node){xx,yy,cnt}); while(q.size()){ int x=q.front().x; int y=q.front().y; int o=q.front().o; q.pop(); in[x][y][o]=0; for(int k=0;k<4;k++){ int nx=x+dx[k]; int ny=y+dy[k]; int nowdis,oo; if(nx<1||nx>m||ny<1||ny>n) continue; if((o==0&&height[nx][ny]>=height[x][y])||(o==1&&height[nx][ny]<=height[x][y])) nowdis=_dis[x][y][o],oo=o; else nowdis=_dis[x][y][o]+1,oo=o^1; if(_dis[nx][ny][oo]>nowdis){ _dis[nx][ny][oo]=nowdis; if(!in[nx][ny][oo]) in[nx][ny][oo]=1,q.push((Node){nx,ny,oo}); } } } for(int i=1;i<=T;i++){ dis[now][i]=std::min(_dis[goal[i][1]][goal[i][2]][0],_dis[goal[i][1]][goal[i][2]][1]); } } void clear(){ maxflow=0; cnt=1;s=k*2+T+1;t=s+1; memset(edge,0,sizeof edge); memset(head,0,sizeof head); } bool bfs(){ std::queue<int> q; memset(d,0,sizeof d); q.push(s);d[s]=1; while(q.size()){ int u=q.front();q.pop(); for(int i=head[u];i;i=edge[i].nxt){ int to=edge[i].to; if(d[to]) continue; if(!edge[i].flow) continue; d[to]=d[u]+1; q.push(to); if(to==t) return 1; } } return 0; } int dinic(int now,int flow){ if(now==t) return flow; int rest=flow,k; for(int i=head[now];i;i=edge[i].nxt){ if(!rest) return flow; int to=edge[i].to; if(!edge[i].flow) continue; if(d[to]!=d[now]+1) continue; k=dinic(to,std::min(rest,edge[i].flow)); if(!k) d[to]=0; edge[i].flow-=k; edge[i^1].flow+=k; rest-=k; } return flow-rest; } bool check(int mid){ clear(); for(int i=1;i<=k*2;i++){ for(int j=1;j<=T;j++){ if(dis[i][j]<=mid) add(i,j+k*2,1),add(j+k*2,i,0); } } for(int i=1;i<=k*2;i++) add(s,i,1),add(i,s,0); for(int i=1;i<=T;i++) add(i+k*2,t,goal[i][3]),add(t,i+k*2,0); int flow=0; while(bfs()) while(flow=dinic(s,0x3f3f3f3f)) maxflow+=flow; return maxflow+mid>=k*2; } signed main(){ scanf("%d%d%d%d",&m,&n,&k,&T); for(int i=1;i<=k*2+1;i++) scanf("%d%d",&toy[i][1],&toy[i][2]); for(int i=1;i<=T;i++) scanf("%d%d%d",&goal[i][1],&goal[i][2],&goal[i][3]); for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++) scanf("%d",&height[i][j]); } for(int i=1;i<=(k<<1);i++) spfa(i,toy[i][1],toy[i][2],(i>k)); int l=0,r=(k<<1)+1; while(l<=r){ int mid=l+r>>1; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); return 0; }
原文地址:https://www.cnblogs.com/YoungNeal/p/8626454.html