建图一时爽,找bug火葬厂…
题意其实就是求一个图的最小割,最小割等于最大流,但是这题点和边都很多,最大流可能会超时,我们就可以转化为对偶图的最短路问题,也就是面看成点,点看成面这样子,经过麻烦的建图之后,跑一下dijk最短路就好了
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=4000005;
const int M=8000005;
const int INF=0x3f3f3f3f;
int n,m,en;
struct Edge{
int v,w,next;
}edge[M];
int cnt,head[N];
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,int w){
edge[cnt]=Edge{
v,w,head[u]};
head[u]=cnt++;
edge[cnt]=Edge{
u,w,head[v]};
head[v]=cnt++;
}
int dis[N];
bool vis[N];
struct node{
int v,w;
bool operator <(node a)const{
return w>a.w;
}
}tmp;
int Dijkstra(int s,int t){
for(int i=0;i<=en;i++){
dis[i]=INF;
vis[i]=false;
}
dis[s]=0;
priority_queue<node> q;
q.push(node{
s,0});
while(!q.empty()){
//printf("Fd\n");
tmp=q.top();
q.pop();
int u=tmp.v;
vis[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
int w=edge[i].w;
//printf("%d %d %d\n",u,v,w);
if(!vis[v] && dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(node{
v,dis[v]});
}
}
}
return dis[t];
}
inline int number(int x,int y,bool up)//每个方格以左上角坐标表示
{
int ret = ((m-1)*(x-1)+y-1)*2+1;
if(up) ret++;
return ret; // S:0 T:1
}
int main(void){
//freopen("data.txt","r",stdin);
scanf("%d%d",&n,&m);
en=2*(n-1)*(m-1)+1;
int t;
//特判
if(n==1 && m==1){
printf("0\n");
}else if(n==1){
int ans=INF;
for(int i=1;i<m;i++){
scanf("%d",&t);
ans=min(ans,t);
}
printf("%d\n",ans);
}else if(m==1){
int ans=INF;
for(int i=1;i<n;i++){
scanf("%d",&t);
ans=min(ans,t);
}
printf("%d\n",ans);
}else{
init();
//横边
for(int i=1;i<=n;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&t);
if(i==1){
//最上面一条直线的边,转化为第一层偶数平面和最上面平面end的边
addEdge(2*j,en,t);
}else if(i==n){
//最下面一条直线的边,转化为最后一层平面和最下面平面0的边
//i就是当前层数,减去2就是第一层还有最后一层,中间的层数乘以每层有2(m-1)个平面
//再加2*j-1就是当前最后一层平面的编号,连上0
addEdge(0,(i-2)*2*(m-1)+2*j-1,t);
}else{
//中间的边连上面一层的下平面和下面一层的上平面
addEdge(2*(m-1)*(i-1)+2*j,2*(i-2)*(m-1)+2*j-1,t);
}
}
}
//竖边,类似的处理方式
for(int i=1;i<=n-1;i++){
for(int j=1;j<=m;j++){
scanf("%d",&t);
if(j==1){
addEdge(0,(i-1)*(m-1)*2+1,t);
}else if(j==m){
//printf("%d %d\n",i*(m-1)*2,number(i,j-1,true));
addEdge(i*(m-1)*2,en,t);
}else{
addEdge((i-1)*(m-1)*2+(j-1)*2,(i-1)*(m-1)*2+2*j-1,t);
}
}
}
//斜边
for(int i=1;i<=n-1;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&t);
//printf("%d %d\n",(i-1)*2*(m-1)+2*(j-1)+1,(i-1)*2*(m-1)+2*j);
addEdge((i-1)*2*(m-1)+2*(j-1)+1,(i-1)*2*(m-1)+2*j,t);
}
}
// for(int i=0;i<=en;i++){
// for(int j=head[i];j!=-1;j=edge[j].next){
// int v=edge[j].v;
// int w=edge[j].w;
// printf("%d %d %d\n",i,v,w);
// }
// }
int ans=Dijkstra(0,en);
printf("%d\n",ans);
}
return 0;
}