bzoj#1001. [BeiJing2006]狼抓兔子&感性理解一下平面图最小割=对偶图最短路

image

考虑随意割边,发现割的边所构成的面应该是相邻的,倘若不相邻就说明还可以再通。

image

比如说这样。

那么只要选择一条最短路径就好了(即最小割)

那么为什么不是从左上走出去呢?

或许可以理解为本来平面图就是左上到右下,割的显然不能平行(左上到右下),要有交才算割(大雾),不过知道相反就好了。

https://darkbzoj.cc/problem/1001

有点卡常,别 #define int long long

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int rd() {
	int sum=0,f=1; char ch=getchar();
	while(ch>'9'||ch<'0') {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0') {
		sum=sum*10+ch-'0'; ch=getchar();
	}
	return sum*f;
}
const int N=(int)(2e6+5),M=1005;
struct edge {
	int nex,to,w;
}e[N*30];
int n,m,s1[M][M],s2[M][M],s3[M][M],id[2][M][M];
int hea[N],cnt,S,T;

void add_edge(int x,int y,int z) {
	e[++cnt].nex=hea[x]; e[cnt].to=y; e[cnt].w=z; hea[x]=cnt;
}

void add(int x,int y,int z) {
	add_edge(x,y,z); add_edge(y,x,z);
}

struct node {
	int x; ll d;
	node(int xx,ll dd) {
		x=xx; d=dd;
	}
	bool operator < (const node &rhs) const {
		return d>rhs.d;
	}
};
const ll inf=(ll)(2e18);
priority_queue<node>q;
bool vis[N];
ll dis[N];
void dij() {
	for(int i=0;i<=T;i++) dis[i]=inf;
	dis[S]=0; q.push(node(S,0));
	while(!q.empty()) {
		int x=q.top().x; q.pop();
		if(vis[x]) continue ;
		vis[x]=1;
		for(int i=hea[x];i;i=e[i].nex) {
			int y=e[i].to;
			if(dis[y]>dis[x]+e[i].w) {
				dis[y]=dis[x]+e[i].w;
				if(!vis[y]) q.push(node(y,dis[y]));
			}
		}
	}
}

signed main() {
	n=rd(); m=rd();
	for(int i=1;i<=n;i++)
		for(int j=1;j<m;j++) s1[i][j]=rd();
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++) s2[i][j]=rd();
	for(int i=1;i<n;i++)
		for(int j=1;j<m;j++) s3[i][j]=rd();
	if(n==1) {
		int qwq=(int)(2e9);
		for(int i=1;i<m;i++) qwq=min(qwq,s1[1][i]);
		cout<<qwq; return 0;
	}
	if(m==1) {
		int qwq=(int)(2e9);
		for(int i=1;i<n;i++) qwq=min(qwq,s2[i][1]);
		cout<<qwq; return 0;
	}
	int tot=0;
	for(int i=1;i<n;i++)
		for(int j=1;j<m;j++) {
			id[0][i][j]=++tot; id[1][i][j]=++tot;
		}
	S=0; ++tot; T=tot;
	for(int i=1;i<n;i++) {
		add(S,id[0][i][1],s2[i][1]);
	}
	for(int i=1;i<m;i++) {
		add(S,id[0][n-1][i],s1[n][i]);
	}	
	for(int i=1;i<m;i++) {
		add(id[1][1][i],T,s1[1][i]);
	}
	for(int i=1;i<n;i++) {
		add(id[1][i][m-1],T,s2[i][m]);
	}
	for(int i=1;i<n;i++) {
		for(int j=1;j<m;j++) {
			add(id[0][i][j],id[1][i][j],s3[i][j]);
			if(i+1<n) add_edge(id[0][i][j],id[1][i+1][j],s1[i+1][j]);
			if(i-1>=1) add_edge(id[1][i][j],id[0][i-1][j],s1[i][j]);
			if(j+1<m) add_edge(id[1][i][j],id[0][i][j+1],s2[i][j+1]);
			if(j-1>=1) add_edge(id[0][i][j],id[1][i][j-1],s2[i][j]);
		}
	}
	dij();
	cout<<dis[T];
	return 0;
}
posted @ 2022-07-21 23:06  FxorG  阅读(30)  评论(0编辑  收藏  举报