普通的最大流算法肯定超时咯
然而这份图有个神奇的特性
最小割必然是从一条边出发,到另一条边结束的连续路径【把区域想想成节点】
然后就用spfa/dij+堆 做
代码风格勿吐槽
/**************************************************************
Problem: 1001
User: HFLSyzx
Language: C++
Result: Accepted
Time:4256 ms
Memory:104880 kb
****************************************************************/
#include<iostream>
#include<queue>
#include<fstream>
using namespace std;
int d[2000000 + 10],n,m;
bool used[2000000 + 10];
const int maxn=2000000 + 10;
struct Edge {
int t, c;
};
struct state
{
int u;
long long d;
};
bool operator < (const state&l,const state&r)
{
return l.d > r.d;
}
vector<Edge> E[maxn+1];
priority_queue<state> q;
int dij(int s,int t)
{
for(int i=0;i<t+1;i++)
d[i]= 1e9;
q.push((state){s,0});
d[s]=0;
while(q.size())
{
state t=q.top();
q.pop();
int u=t.u;
if(used[u])
continue;
used[u] = 1;
for(int j = 0; j < E[u].size(); j++) {
Edge &e = E[u][j];
if(d[e.t] > d[u] + e.c) {
d[e.t] = d[u] + e.c;
q.push((state){e.t, d[e.t]});
}
}
}
return d[t];
}
void addEdge(int s, int t, int c) {
Edge ee;
ee.c=c;
ee.t=t;
E[s].push_back(ee);
ee.t=s;
E[t].push_back(ee);
}
int main()
{
int c;
//freopen("aa.txt","r",stdin);
cin>>n>>m;
if(n==1||m==1)
{
if(n==m) {
printf("0\n");
return 0;
}
if(n==1)
{
int min=~0U>>1;
for(int i=1;i<=m-1;i++) {
scanf("%d",&c);
if(c<min)
min=c;
}
printf("%d\n",min);
}
if(m==1)
{
int min=~0U>>1;
for(int i=1;i<=n-1;i++) {
scanf("%d",&c);
if(c<min)
min=c;
}
printf("%d\n",min);
}
return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m-1;j++)
{
cin>>c;
if(i==1)
addEdge(0,j,c);
else if(i==n)
addEdge((2*(n-1)-1)*(m-1)+j,2*(n-1)*(m-1)+1,c);
else
addEdge((2*(i-1)-1)*(m-1)+j,2*(i-1)*(m-1)+j,c);
}
for(int i=1;i<=n-1;i++)
for(int j=1;j<=m;j++)
{
cin>>c;
if(j==1)
addEdge((2*i-1)*(m-1)+1,2*(n-1)*(m-1)+1,c);
else if(j==m)
addEdge(0,(2*i-1)*(m-1),c);
else
addEdge(2*(i-1)*(m-1)+j-1,2*(i-1)*(m-1)+j-1+m,c);
}
for(int i=1;i<=n-1;i++)
for(int j=1;j<=m-1;j++)
{
cin>>c;
addEdge(2*(i-1)*(m-1)+j,2*(i-1)*(m-1)+j+m-1,c);
}
int d=dij(0,2*(n-1)*(m-1)+1);
cout<<d<<endl;
return 0;
}