【链接】
bzoj1001
【题目大意】
给你一张网格图,让你将图中的删去一些边,从而使没有一条路径从左上角到右下角,答案即为所有删去边的加和的最小值。
【解题报告】
本题一看就发现是最小割,但是时间有些高,所以就换一个思路想,发现似乎可以用最短路做,因为是求一条权值最小的路径,果断刷spfa,将边转化成点,建边只需要将每个小三角形之间的边互相建边即可。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=2996005,maxm=11976017,INF=((1<<30)-1)*2+1;
int n,m,ans,tot,lnk[maxn],que[maxn],dst[maxn],w[maxn],son[maxm],nxt[maxm];
bool vis[maxn];
inline int Read()
{
int res=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res;
}
int Getid(int id,int x,int y)
{
if (id==0) return (x-1)*(m-1)+y;
else if (id==1) return n*(m-1)+(x-1)*m+y;
else return n*(m-1)+(n-1)*m+(x-1)*(m-1)+y;
}
int Add(int x,int y)
{
son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
int Spfa()
{
memset(vis,0,sizeof(vis));
memset(dst,63,sizeof(dst));
int hed=0,til=0,id;
for (int i=1; i<m; i++) id=Getid(0,n,i),que[++til]=id,vis[id]=1,dst[id]=0;
for (int i=1; i<n; i++) id=Getid(1,i,1),que[++til]=id,vis[id]=1,dst[id]=0;
while (hed!=til)
{
hed=(hed+1)%maxn;
int x=que[hed]; vis[x]=0;
for (int j=lnk[x]; j; j=nxt[j])
if (dst[x]+w[x]<dst[son[j]])
{
dst[son[j]]=dst[x]+w[x];
if (!vis[son[j]])
{
vis[son[j]]=1; til=(til+1)%maxn; que[til]=son[j];
if (dst[que[til]]<dst[que[(hed+1)%maxn]]) swap(que[til],que[(hed+1)%maxn]);
}
}
}
for (int i=1; i<m; i++) id=Getid(0,1,i),ans=min(ans,dst[id]+w[id]);
for (int i=1; i<n; i++) id=Getid(1,i,m),ans=min(ans,dst[id]+w[id]);
return 0;
}
int main()
{
freopen("1001.in","r",stdin);
freopen("1001.out","w",stdout);
n=Read(); m=Read(); tot=0; ans=1<<30;
if (n==1&&m==1) {printf("0"); return 0;}
for (int i=1; i<=n; i++)
for (int j=1; j<m; j++)
w[Getid(0,i,j)]=Read();
for (int i=1; i<n; i++)
for (int j=1; j<=m; j++)
w[Getid(1,i,j)]=Read();
for (int i=1; i<n; i++)
for (int j=1; j<m; j++)
w[Getid(2,i,j)]=Read();
for (int i=1; i<n; i++)
for (int j=1; j<m; j++)
{
int X1=Getid(0,i+1,j),X2=Getid(1,i,j),X3=Getid(2,i,j);
Add(X1,X2); Add(X1,X3);
Add(X2,X1); Add(X2,X3);
Add(X3,X1); Add(X3,X2);
//以上是将左下小三角形之间的边建边
X1=Getid(0,i,j),X2=Getid(1,i,j+1),X3=Getid(2,i,j);
Add(X1,X2); Add(X1,X3);
Add(X2,X1); Add(X2,X3);
Add(X3,X1); Add(X3,X2);
//以上是将右上小三角形之间的边建边
}
Spfa();
printf("%d",ans);
return 0;
}