BZOJ 2547(匈牙利算法-任意边的处理)
小明的爸爸给他买了一盒玩具兵,其中有 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。
● 天兵技术全面,移动不受任何限制。
可是没玩几次,小明就发现这个游戏太难了,他常常玩了好半天也达不到目的。于是,他设计了一种“超能力”,每使用一次超能力的时候,虽然不能移动任何一个玩具兵,但可对它们进行任意多次交换操作,每次交换两个玩具兵。等这次超能力使用完后又可和平常一样继续移动这些玩具兵。借助强大的超能力,这个游戏是容易玩通的,但是怎样才能让使用超能力的次数最少呢?
第一行包含四个整数: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。
仅包含一行,即使用超能力的最小次数T。
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<cctype>#include<iostream>#include<functional>#include<algorithm>#include<queue>using namespace std;#define MAXN (100+10)#define MAXM (100+10)#define MAXK (100+10)#define MAXT (100+1+10)#define COST (bool(type)^(f[x][y]&1))?(h[x][y]<h[x+path[i][0]][y+path[i][1]]):(h[x][y]>h[x+path[i][0]][y+path[i][1]])const int path[4][2]={{0,1},{1,0},{-1,0},{0,-1}};int n,m,k,t,h[MAXM][MAXN],f[MAXM][MAXN];queue< pair<int,int> > q;bool inside(int x,int y){if (1<=x&&x<=m&&1<=y&&y<=n) {/*cout<<'A'<<x<<' '<<y<<endl;*/ return 1;}else return 0;}void bfs(bool type,int x,int y) //type-> 0 upper 1 lower{memset(f,127,sizeof(f));f[x][y]=0;q.push(make_pair(x,y));while (!q.empty()){pair<int ,int> now=q.front();int &x=now.first,&y=now.second;for (int i=0;i<4;i++){int c=COST;if (inside(x+path[i][0],y+path[i][1]))if (f[x+path[i][0]][y+path[i][1]]>f[x][y]+c){//cout<<(x+path[i][0])<<' '<<(y+path[i][1])<<endl;f[x+path[i][0]][y+path[i][1]]=f[x][y]+c;q.push(make_pair(x+path[i][0],y+path[i][1]));}}q.pop();}}pair<int,int> A[MAXT],B[MAXT];int cost[MAXK][MAXT],a[MAXT];bool b[MAXT];bool find(int x,int maxcost){for (int i=1;i<=2*k+1;i++) if (!b[i]&&cost[x][i]<=maxcost){b[i]=1;if (a[i]==0) {a[i]=x;return 1;}if (find(a[i],maxcost)) {a[i]=x; return 1;}}return 0;}int hopcroft(int maxcost){memset(a,0,sizeof(a));int ans=0;for (int i=1;i<=2*k;i++){memset(b,0,sizeof(b));if (find(i,maxcost)) ans++;}//cout<<ans<<endl;return ans;}int b_search(){int l=0,r=2*k;while (l<r){m=(l+r)>>1;if (hopcroft(m)+m>=2*k) r=m;else l=m+1;}return l;}int main(){//freopen("2547.in","r",stdin);scanf("%d%d%d%d",&m,&n,&k,&t);for (int i=1;i<=2*k+1;i++) scanf("%d%d",&A[i].first,&A[i].second);int size=1;for (int i=1;i<=t;i++){int r;scanf("%d%d%d",&B[size].first,&B[size].second,&r);size++;for (r--;r;r--,size++) B[size]=B[size-1];}for (int i=1;i<=m;i++) for (int j=1;j<=n;j++) scanf("%d",&h[i][j]);/*bfs(1,1,2);for (int i=1;i<=m;i++){for (int j=1;j<=n;j++) cout<<f[i][j]<<' ';cout<<'\n';}*/for (int i=1;i<=2*k;i++){bfs((i>k),A[i].first,A[i].second);for (int j=1;j<=2*k+1;j++){cost[i][j]=f[B[j].first][B[j].second];//cout<<i<<' '<<j<<' '<<cost[i][j]<<endl;}}cout<<b_search()<<endl;return 0;}