版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88546790
题目
之前看有人写博客:NOI2010原题重测中他第一次打最小割转最短路就A了。
学习了(200行的)最左转线和点定位之后,我深深的膜拜他。
今日一见此题。
好像我也可以。
不用最左转线,不用点定位。
直接人类智慧。
注意反向边也需要连,最小割不一定只包含一个方向的边。
注意0边也需要连,因为不连等同于inf。
AC Code:
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define maxn 300005
#define maxm 2000005
using namespace std;
int n;
int info[maxn],Prev[maxm],to[maxm],cst[maxm],cnt_e=1;
void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=c; }
void Line(int u,int v,int c){ Node(u,v,c); }
int dis[maxn];
bool usd[maxn];
int main()
{
scanf("%d",&n);
int S = n * n + 1 , T = n * n + 2;
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(i == 1) Line(S,(i-1)*n+j,x);
else if(i == n+1) Line((i-2)*n+j,T,x);
else Line((i-2)*n+j,(i-1)*n+j,x);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
{
int x;
scanf("%d",&x);
if(j == 1) Line((i-1)*n+j,T,x);
else if(j == n+1) Line(S,(i-1)*n+j-1,x);
else Line((i-1)*n+j,(i-1)*n+j-1,x);
}
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(i == 1) Line((i-1)*n+j,S,x);
else if(i == n+1) Line(T,(i-2)*n+j,x);
else Line((i-1)*n+j,(i-2)*n+j,x);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
{
int x;
scanf("%d",&x);
if(j == 1) Line(T,(i-1)*n+j,x);
else if(j==n+1) Line((i-1)*n+j-1,S,x);
else Line((i-1)*n+j-1,(i-1)*n+j,x);
}
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
memset(dis,0x3f,sizeof dis);
q.push(make_pair(0,S)),dis[S] = 0;
for(int now;!q.empty();)
{
now = q.top().second , q.pop();
if(usd[now]) continue;
usd[now] = 1;
for(int i=info[now];i;i=Prev[i])
if(dis[to[i]] > dis[now] + cst[i])
{
dis[to[i]] = dis[now] + cst[i];
q.push(make_pair(dis[to[i]],to[i]));
}
}
printf("%d\n",dis[T]);
}