这道题贼坑人,交了5遍才过,最后实在过不去了,拿来了黄学长的代码对拍,发现自己点数的数组开小了+没有判断成一条链时的情况,其实具体我也不太知道为什么我的点过不去,但是用黄学长那个加点法是能过得去m=1的数据的,做法参见《两极相通——浅析最大—最小定理在信息学竞赛中的应用》——周东。
首先这个图是一个裸的最小割,但是呢,因为边数太大了,会超时,又因为它是一个平面图,根据欧拉公式,可以把他的面,转换成它的点,把他的边做一条连接两个面的边,根据这些做出一个反图,然后这个反图的边就是一条割边,所以反图的一条路就是一个割,所以反图的最短路就是平面图的最小割,根据以上,制图,跑一边最短路就出来了,所以这个图的坑点其实还是在作图上,不知道为什么我是把每一行顺次做出(m=4)1.2.3.4.5.6之类的,但是过不去m=1的情况,hzwer是把每一个做成(m=4)1.4.2.5.3.6,他这样的作图方式就能过得去,然而本质并无区别好吗,只不过把点改了一下名字而已。
还有一个坑点就是,他的面最大是(1000-1) * (1000-1) * 2,我一开始把数组开成了1000000,然后终点设为1000001,然后就WA了好几次,也是要注意细节吧,毕竟今天刚刚开始刷BZOJ,感觉这种OJ,真的蛮磨炼个人水平的,题难到不说,主要是他不会告诉你测试数据第几个点错了,也不会告诉你过了几个点,或者你错的点的那个数据,对于细节的把控也是要慢慢提高的。
附代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
const int N=2000005;
int n,m,d[N],inq[N],head[N],te;
struct edge{
int u,v,next,w;
}e[8000010];
inline int getc()
{
register int a;register char c;
while(c=getchar(),c<'-');a=c-'0';
while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0';
return a;
}
int add(int u,int v,int w)
{
e[++te].v=v;
e[te].w=w;
e[te].next=head[u];
head[u]=te;
}
void spfa()
{
queue<int>q;
memset(d,0x3f,sizeof(d));
memset(inq,0,sizeof(inq));
d[0]=0;
inq[0]=1;
q.push(0);
while(!q.empty())
{
int u=q.front();
inq[u]=0;
q.pop();
for (int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if (d[v]>d[u]+e[i].w)
{
d[v]=d[u]+e[i].w;
if (!inq[v])
{
inq[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
// freopen("std.in","r",stdin);
// freopen("std.out","w",stdout);
int ed=2000003;
te=0;
memset(head,0,sizeof(head));
n=getc();m=getc();
if (m==1)
{
int k=0x3f3f3f3f;
for (int i=1;i<n;i++)
{
int w=getc();
k=min(w,k);
}
cout<<k;
return 0;
}
int w,u,v;
for (int i=1;i<=n;i++)
{
u=(i-1)*(m-1)*2;
for (int j=1;j<m;j++)
{
u+=2;v=u-2*m+1;
w=getc();
if (i==1)add(0,u,w),add(u,0,w);
else if (i==n)add(v,ed,w),add(ed,v,w);
else
{
add(u,v,w);
add(v,u,w);
}
}
}
for (int i=1;i<n;i++)
{
u=(i-1)*(m-1)*2+1;
for (int j=1;j<=m;j++)
{
w=getc();
if (j==1)add(ed,u,w),add(u,ed,w);
else if (j==m)add(0,u-1,w),add(u-1,0,w);
else add(u,u-1,w),add(u-1,u,w);
u+=2;
}
}
for (int i=1;i<n;i++)
{
u=(i-1)*(m-1)*2+1;
for (int j=1;j<m;j++)
{
w=getc();
add(u,u+1,w);
add(u+1,u,w);
u+=2;
}
}
spfa();
cout<<d[ed]<<endl;
// fclose(stdin);
// fclose(stdout);
}
1013

被折叠的 条评论
为什么被折叠?



