题解 UVA1376 【Animal Run】
双倍经验题 q w q q q qwqqq qwqqq
如果您 A C AC AC 了本题,您可以去隔壁洛谷P4001狼抓兔子
(完全一样的题目,只是需要更改一下格式)
本题表面上看着像是网络流最小割,但是网络流蒟蒻不会的复杂度可能无法接受
所以本题是一个最短路
所以需要把图转为对偶图
将原图内围成的每一个三角形看作一个虚点
因为要将起点和终点分割开,所以所练的路径异地逆回购是从左或下到达右或上
所以需要 2 2 2 个点,一个点指向左和下的点,一个点被上或右的所有点指向
其余的店指向与之相邻的点
边权为删除该边的代价
所以很建好图跑一遍 d i j k s t r a dijkstra dijkstra 就行了
P . S . P.S. P.S. 可能存在 n n n 或 m = 1 m=1 m=1 的情况,直接输出所有边中的最小值即可
具体细节见代码(蒟蒻写的可能还有一些复杂)
下面附上蒟蒻的代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read()
{
int r,s=0,c;
for(;!isdigit(c=getchar());s=c);
for(r=c^48;isdigit(c=getchar());(r*=10)+=c^48);
return s^45?r:-r;
}
const int M=2100000,inf=2e9+7;
int n,m,minn,t;
inline int calc(int x,int y,int pos)
{//pos=1下,pos=2 上
int ans=(2*m-2)*(x-1)+2*y-1;
if(pos==2)ans++;
return ans;
}
struct edge
{
int to,next,val;
}mem[M<<2];
int head[M],cnt;
inline void add(int u,int v,int val)
{
mem[++cnt].next=head[u];
mem[cnt].to=v;
mem[cnt].val=val;
head[u]=cnt;
}
struct node
{
int val,num;
friend bool operator < (node a,node b)
{
return a.val>b.val;
}
}f,ff;
int d[M];
bool vis[M];
inline void dijkstra(int s)
{
int num=2*n*m-2*n-2*m+4;
for(int i=1;i<=num;i++)
d[i]=inf,vis[i]=0;
priority_queue<node> q;
f.num=s,f.val=0;
d[s]=0;
q.push(f);
while(!q.empty())
{
f=q.top();
q.pop();
if(vis[f.num])continue;
vis[f.num]=1;
for(int i=head[f.num];i>0;i=mem[i].next)
{
int to=mem[i].to;
if(d[to]>d[f.num]+mem[i].val)
{
d[to]=d[f.num]+mem[i].val;
ff.num=to,ff.val=d[to];
q.push(ff);
}
}
}
}
int main()
{
while(1)
{
minn=inf;
n=read(),m=read();
if(n==0||m==0)
return 0;
memset(mem,0,sizeof(mem));
memset(head,0,sizeof(head));
cnt=0;
int val;
for(int i=1;i<=n;++i)//横边
for(int j=1;j<m;++j)
{
val=read();
minn=min(minn,val);
if(i==1)
add(calc(i,j,2),2*n*m-2*n-2*m+4,val);
else if(i==n)
add(2*n*m-2*n-2*m+3,calc(i-1,j,1),val);
else
add(calc(i-1,j,1),calc(i,j,2),val),add(calc(i,j,2),calc(i-1,j,1),val);
}
for(int i=1;i<n;++i)//纵边
for(int j=1;j<=m;++j)
{
val=read();
minn=min(minn,val);
if(j==1)
add(2*n*m-2*n-2*m+3,calc(i,j,1),val);
else if(j==m)
add(calc(i,j-1,2),2*n*m-2*n-2*m+4,val);
else
add(calc(i,j-1,2),calc(i,j,1),val),add(calc(i,j,1),calc(i,j-1,2),val);
}
for(int i=1;i<n;++i)//斜边
for(int j=1;j<m;++j)
{
val=read();
minn=min(minn,val);
add(calc(i,j,1),calc(i,j,2),val),add(calc(i,j,2),calc(i,j,1),val);
}
if(n==1||m==1)
{
printf("%d\n",minn);
return 0;
}
dijkstra(2*n*m-2*n-2*m+3);
t++;
printf("Case %d: Minimum = %d\n",t,d[2*n*m-2*n-2*m+4]);
}
return 0;
}