[P4001 [ICPC-Beijing 2006]狼抓兔子]
题解:
这个题目已经给你建好图了,一看就是一个最小割,但是如果真的用最小割来写,肯定会 \(TLE\) ,看了题解发现这个是一个 网络流最小割平面图转对偶图求最短路 。
题解推荐博客:https://www.cnblogs.com/lher/p/7856451.html
看完题解之后,就可以自己开始写了。
注意这个每一个区域的点,是怎么定义的,因为一个格子有两个区域(也就是两个点),所以每一个格子的位置是 \((i,j)\) 可以转化为数字 \((i-1)*(m-1)+j\) ,因为每一个格子分成左右两个,所以继续转化,\(x=((i-1)*(m-1)+j)*2\) ,这样左边这个就等于 \(x-1\) ,右边这个区域就是 \(x\) ,最后就直接建图,跑最短路就可以了。
交的时候如果用 \(vector\) 建图,注意开 \(O2\) 优化。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
#define debug(x) printf("debug:%s=%d\n",#x,x);
//#define debug(x) cout << #x << ": " << x << endl;
using namespace std;
typedef long long ll;
const int maxn = 1e3+5;
inline int read(){
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
int row[maxn][maxn],col[maxn][maxn],a[maxn][maxn],t,n,m;
struct node{
int u,v,w;
node(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
struct heapnode{
int d,u;
heapnode(int d,int u) : d(d),u(u) {}
bool operator<(const heapnode &a) const{
return a.d<d;
}
};
vector<node>e[2*maxn*maxn];
void add(int u,int v,int w){
// printf("u=%d v=%d w=%d\n",u,v,w);
if(u<0||v<0) return ;
if(u>2*(n-1)*(m-1)+1||v>2*(n-1)*(m-1)+1) return;
e[u].push_back(node(u,v,w));
e[v].push_back(node(v,u,w));
}
ll d[2*maxn*maxn];
bool vis[2*maxn*maxn];
priority_queue<heapnode>que;
void dij(int s){
while(!que.empty()) que.pop();
for(int i=0;i<=t+10;i++) d[i]=inf64;
d[s]=0;
que.push(heapnode(0,s));
while(!que.empty()){
heapnode x=que.top();que.pop();
int u=x.u;
if(vis[u]) continue;
vis[u]=1;
for(int i=0;i<e[u].size();i++){
node now=e[u][i];
if(d[now.v]>d[u]+now.w){
d[now.v]=d[u]+now.w;
que.push(heapnode(d[now.v],now.v));
}
}
}
}
int main(){
// scanf("%d%d",&n,&m);
n = read(),m = read();
int s=0;
t=2*(n-1)*(m-1)+1;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++) {
row[i][j]=read();
// scanf("%d",&row[i][j]);
}
for(int i=1;i<n;i++) {
for(int j=1;j<=m;j++) {
col[i][j]=read();
// scanf("%d",&col[i][j]);
}
}
for(int i=1;i<n;i++) {
for(int j=1;j<m;j++) {
a[i][j]=read();
// scanf("%d",&a[i][j]);
}
}
if(n==1){
int ans = inf;
for(int j=1;j<m;j++) ans=min(ans,row[1][j]);
printf("%d\n",ans);
return 0;
}
if(m==1){
int ans = inf;
for(int i=1;i<n;i++) ans=min(ans,col[i][1]);
printf("%d\n",ans);
return 0;
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
int u = ((i-1)*(m-1)+j)*2,v = u - 1;
if(u>0&&u<=2*(n-1)*(m-1)) add(u,v,a[i][j]);
int x = ((i-1)*(m-1)+j+1)*2-1;
if(x>0&&x<=2*i*(m-1)&&u>0&&u<=2*(n-1)*(m-1)) add(u,x,col[i][j+1]);
int y = (i*(m-1)+j)*2;
if(y>0&&y<=2*(n-1)*(m-1)) add(v,y,row[i+1][j]);
// printf("i=%d j=%d u=%d v=%d x=%d y=%d\n",i,j,u,v,x,y);
}
}
for(int i=1;i<n;i++){
int u = ((i-1)*(m-1)+1)*2-1,v = i*(m-1)*2;
if(u<0||v<0) continue;
if(u<=2*(n-1)*(m-1)) add(s,u,col[i][1]);
if(v<=2*(n-1)*(m-1)) add(t,v,col[i][m]);
}
// printf("\n");
for(int j=1;j<m;j++){
int u = ((n-2)*(m-1)+j)*2-1,v=j*2;
if(u<0||v<0) continue;
if(u<=2*(n-1)*(m-1)) add(s,u,row[n][j]);
if(v<=2*(n-1)*(m-1)) add(t,v,row[1][j]);
// printf("u=%d v=%d col=%d row=%d\n",u,v,row[n-1][j],row[1][j]);
}
dij(s);
printf("%lld\n",d[t]);
return 0;
}