qoj6279 Honeycomb

题意

给出一个 \(n\times m\) 个六边形的网格,字符画形式给出,每两个格子之间可能有墙或无墙,问对每对不同的点来说使它们不连通增加的墙数量之和为多少。

\(n,m\le 100\),六边不全为墙的格子数量 \(\le 3000\)

思路

最大的一坨。

对每对不同的点求最小割,显然最小割树,直接模拟建图即可。

又因最大答案不超过 \(6\),所以跑网络流不会超时。

注意不要用 ISAP,会死的很惨。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
namespace mf{
	const int N=3010,INF=0x3f3f3f3f;
	struct node{int ed,w,id;};
	vector<node>e[N];
	int n,S,T;
	int dep[N],now[N];
	void init(int nn){
		for(int i=1;i<=nn;i++)
			e[i].clear();
		n=nn;
	}
	bool bfs(){
		memset(dep,-1,sizeof(dep));
		queue<int>q;
		q.push(S);
		dep[S]=0;
		while(!q.empty()){
			int t=q.front();
			q.pop();
			for (int i=0;i<e[t].size();i++){
				int ed=e[t][i].ed;
				if (dep[ed]==-1&&e[t][i].w){
					dep[ed]=dep[t]+1;
					q.push(ed);
				}
			}
		}
		memset(now,0,sizeof(now));
		return dep[T]!=-1;
	}
	int dfs(int st, int lim){
		if(st==T)
			return lim;
		for(int i=now[st];i<e[st].size();i++){
			now[st]=i;
			int ed=e[st][i].ed;
			if(dep[ed]==dep[st]+1&&e[st][i].w){
				int tmp=dfs(ed,min(e[st][i].w,lim));
				if(tmp){
					e[st][i].w-=tmp;
					e[ed][e[st][i].id].w+=tmp;
					return tmp;
				}
			}
		}
		return 0;
	}
	int dinic(){
		int r=0,flow;
		while(bfs())
			while(flow=dfs(S,INF))
				r+=flow;
		return r;
	}
	void add(int st,int ed,int w){
		int sti=e[st].size();
		int edi=e[ed].size();
		e[st].push_back({ed,w,edi});
		e[ed].push_back({st,0,sti});
	}
}
namespace go{
	struct node{
		int x,y,w;
	};
	vector<node> yt,t[3005];
	void add(int x,int y,int v){
		yt.push_back({x,y,v});
	}
	int n,a[3005],tmp[3005],dep[3005],f[3005],ans;
	bool can[3005];
	void build(int l,int r){
		if(l>=r) return;
		mf::init(n);
		int x=a[l],y=a[r];
		mf::S=x,mf::T=y;
		for(node v:yt)
			mf::add(v.x,v.y,v.w),mf::add(v.y,v.x,v.w);
		int w=mf::dinic();
		t[x].push_back({y,w});
		t[y].push_back({x,w});
		int tl=l-1,tr=r+1;
		for(int i=l;i<=r;i++){
			if(mf::dep[a[i]]!=-1) tmp[++tl]=a[i];
			else tmp[--tr]=a[i];
		}
		for(int i=l;i<=r;i++)
			a[i]=tmp[i];
		build(l,tl);
		build(tr,r);
	}
	void dfs(int x,int fa){
		if(f[x]!=0x3f3f3f3f) ans+=f[x];
		for(node v:t[x])
			if(v.x!=fa)
				f[v.x]=min(f[x],v.y),dfs(v.x,x);
	}
}
int T,n,m,id[1005][1005],tot;
string s[3005];
signed main(){
	cin>>T;
	for(int I=1;I<=T;I++){
		tot=0;
		go::yt.clear();
		go::ans=0;
		cin>>n>>m;
		cin.ignore();
		for(int i=1;i<=4*n+3;i++){
			getline(cin,s[i]);
		}
		for(int i=1;i<=4*n+3;i++){
			for(int j=0;j<s[i].length();j++){
				if(s[i][j]=='*') id[i][j]=++tot;
			}
		}
		for(int i=2;i<=4*n+3;i++){
			for(int j=1;j<s[i].length();j++){
				if(s[i-1][j-1]=='+'&&s[i+1][j+1]=='+'&&s[i][j]==' '){
					go::add(id[i+1][j-3],id[i-1][j+3],1);
				}
				if(s[i+1][j-1]=='+'&&s[i-1][j+1]=='+'&&s[i][j]==' '){
					go::add(id[i-1][j-3],id[i+1][j+3],1);
				}
				if(j>1&&j<s[i].length()-2&&s[i][j-2]=='+'&&s[i][j+2]=='+'&&s[i][j]==' '){
					go::add(id[i-2][j],id[i+2][j],1);
				}
			}
		}
		for(int i=1;i<=tot;i++)
			go::t[i].clear();
		go::n=tot;
		for(int i=1;i<=tot;i++)
			go::a[i]=i;
		go::build(1,tot);
		for(int i=1;i<=tot;i++)
			go::f[i]=0x3f3f3f3f,go::dfs(i,0);
		cout<<"Case #"<<I<<": "<<go::ans/2<<endl;
	}
	return 0;
}
posted @ 2025-09-10 08:03  WuMin4  阅读(17)  评论(0)    收藏  举报