zoukankan      html  css  js  c++  java
  • BZOJ 2547: [Ctsc2002]玩具兵(二分答案+二分图匹配)

    传送门

    解题思路

      可以发现天兵不用管,答案的一个上界是(2*k),就是天兵一个个换。刚开始写了个拆(6)点的网络流,调了半天发现自己假了。。说说正解,首先可以发现交换士兵其实就是种类的交换,那么可以对于每一个点算出它距离所有点的距离,距离就是最少换几次,这个可以(spfa)求出,之后发现这个很像二分图匹配,可以二分答案表示用几次超能力,然后跑二分图匹配即可。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    const int N=105;
    
    inline int rd(){
    	int x=0,f=1; char ch=getchar();
    	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    
    int n,m,k,T,val[N][N],dis[N][N],xx[N],yy[N],match[N];
    int h[N][N],tx[N],ty[N],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},ans,tot;
    bool vis[N][N],use[N];
    queue<int> Q[2];
    
    void bfs(int x,int y,int tmp){
    	memset(vis,false,sizeof(vis));
    	memset(dis,0x3f,sizeof(dis));
    	dis[x][y]=0; vis[x][y]=1;
    	Q[0].push(x); Q[1].push(y);
    	int i,j,ii,jj,t;
    	while(Q[0].size()){
    		i=Q[0].front(); Q[0].pop();
    		j=Q[1].front(); Q[1].pop();
    		vis[i][j]=0;
    		for(int k=0;k<4;k++){
    			ii=i+dx[k]; jj=j+dy[k];
    			if(ii<1 || ii>n || jj<1 || jj>m) continue;
    			if((dis[i][j]&1)==tmp){
    				if(h[ii][jj]<h[i][j]) t=1;
    				else t=0;
    			}
    			else {
    				if(h[ii][jj]>h[i][j]) t=1;
    				else t=0;
    			}
    			if(dis[i][j]+t<dis[ii][jj]){
    				dis[ii][jj]=dis[i][j]+t;
    				if(!vis[ii][jj]) Q[0].push(ii),Q[1].push(jj),vis[ii][jj]=1;
    			}
    		}
    	}
    }
    
    bool dfs(int x,int lim){
    	for(int i=1;i<=tot;i++){
    		if(val[x][i]>lim || use[i]) continue;
    		use[i]=1;
    		if(!match[i] || dfs(match[i],lim)) {
    			match[i]=x; return 1;
    		}
    	}
    	return 0;
    }
    
    inline bool check(int lim){
    	int ret=0;
    	memset(match,0,sizeof(match));
    	for(int i=1;i<=2*k;i++){
    		memset(use,0,sizeof(use));
    		ret+=dfs(i,lim);
    	}
    	return ret+lim>=2*k;
    }
    
    int main(){
    	n=rd(),m=rd(),k=rd(),T=rd(); int x,y,z;
    	for(int i=1;i<=2*k+1;i++) xx[i]=rd(),yy[i]=rd();
    	for(int i=1;i<=T;i++){
    		x=rd(),y=rd(),z=rd();
    		while(z--) tx[++tot]=x,ty[tot]=y;
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++) h[i][j]=rd();
    	for(int i=1;i<=2*k;i++){
    		if(i<=k) bfs(xx[i],yy[i],0);
    		else bfs(xx[i],yy[i],1);
    		for(int j=1;j<=tot;j++) val[i][j]=dis[tx[j]][ty[j]];
    	}
    	int l=0,r=(k<<1),mid;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(check(mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C# 委托/Func() 中 GetInvocationList() 方法的使用 | 接收委托多个返回值
    蒋廷黻著《中国近代史》-中国近代屈辱史读后感
    ASP.NET Core 上传多文件 超简单教程
    Python
    Python
    Python
    Python
    Python
    Python
    Python
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10434219.html
Copyright © 2011-2022 走看看