狼抓兔子

link

明显的最小割,但数据范围比较大(虽然据讨论可以水过但我没去试)。于是考虑使用正确复杂度的算法,想到对偶图。然后这就是一个对偶图的板子了,图都给你画出来了正常加边跑最短路即可。需要注意的是加边的时候要加无向边,在这个地方卡了一会。每日维生素B。

#include<bits/stdc++.h>
//#define feyn
const int N=1010;
const int M=N*N*2;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

struct edge{
	int t,v,next;
}e[M<<2];
int esum,head[M];
inline void adde(int fr,int to,int val){
	e[++esum]=(edge){to,val,head[fr]};head[fr]=esum;
}
inline void add(int fr,int to,int val){
	adde(fr,to,val);adde(to,fr,val);
}

struct node{
	int pl,dis;
};
inline bool operator <(node s1,node s2){
	return s2.dis<s1.dis;
}
priority_queue<node>q;
int dis[M];

int m,n,in;
int cnt,ss,tt,a[N][N][2];

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	ss=++cnt;tt=++cnt;
	for(int i=1;i<m;i++){
		for(int j=1;j<n;j++){
			a[i][j][0]=++cnt;
			a[i][j][1]=++cnt;
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<n;j++){
			read(in);
			if(i==1)add(a[i][j][1],tt,in);
			else if(i==m)add(ss,a[i-1][j][0],in);
			else add(a[i][j][1],a[i-1][j][0],in);
		}
	}
	for(int i=1;i<m;i++){
		for(int j=1;j<=n;j++){
			read(in);
			if(j==1)add(ss,a[i][j][0],in);
			else if(j==n)add(a[i][j-1][1],tt,in);
			else add(a[i][j-1][1],a[i][j][0],in);
		}
	}
	for(int i=1;i<m;i++){
		for(int j=1;j<n;j++){
			read(in);
			add(a[i][j][0],a[i][j][1],in);
		}
	}
	memset(dis,0x3f,sizeof(dis));
	dis[ss]=0;q.push((node){ss,0});
	while(!q.empty()){
		node now=q.top();q.pop();
		int wh=now.pl,nd=now.dis;
		if(nd>dis[wh])continue;
		for(int i=head[wh],th;i;i=e[i].next){
			int now_d=dis[wh]+e[i].v;
			if(now_d>=dis[th=e[i].t])continue;
			dis[th]=now_d;q.push((node){th,dis[th]});
		}
	}
	printf("%d\n",dis[tt]);
	
	return 0;
}
posted @ 2022-07-24 21:28  Feyn618  阅读(37)  评论(0编辑  收藏  举报