bzoj1001

这道题,n*m=1000*1000=100 0000

网络流理论上过不了,可是因为数据太弱了,网络流dinic也可以过。

然而这个团队只有我用最短路QAQ。


原题就是一个最小割的典型模型,我们可以把原图的每一个面(三角形)当成一个点,再虚拟一个源和一个汇,拥有上边界或右边界(边界!)的连到源,下边界或左边界的连到汇。有公共边的三角形相连。这样,我最短路中的每一个路径都是一个割。构图很巧妙,把割的权值转移到了最短路的边上。

具体可以搜索:两级相通————浅析最大最小定理在信息学竞赛中的应用 By 周冬

注意要建双向边。当n=1或m=1时特别对待就好了。注意数组大小。

然后最短路算法乱做就可以了。

我用的SPFA:<-却有3000ms   别人网络流才2000ms,不服。

#include<cstdio>
#include<cstdlib>
#include<cstring>
int n,m;
int S,T;
struct mod{int x,y,z,next;};
mod q[6000005];
int first[4000005];
bool v[4000005];
int s[4000005];
int t[4000005];
int len=0;
void ins(int x,int y,int z)
{
 len++;
 q[len].x=x;
 q[len].y=y;
 q[len].z=z;
 q[len].next=first[x];
 first[x]=len; 
  
 len++;
 q[len].x=y;
 q[len].y=x;
 q[len].z=z;
 q[len].next=first[y];
 first[y]=len;
}
int main()
{
    scanf("%d%d",&n,&m);
    if(n==1||m==1)  
    { 
        if(n>m) {int tt=n;n=m;m=tt;}
        int ans=999999999;  
        for(int i=1;i<m;++i)  
        { 
            int o;  
            scanf("%d",&o); 
            if(o<ans) ans=o;  
        } 
        printf("%d\n", ans);  
        return 0; 
    } 
    S=0,T=(n-1)*(m-1)*2+1;
    for(int i=0;i<=T;i++)
    first[i]=-1;
    for(int i=1;i<=n;i++)
     for(int j=1;j<m;j++)
     {
      int o;
      scanf("%d",&o);
      if(i==1)
      ins(S,(i-1)*(m-1)*2+j*2-1,o);
      else if (i==n)
      ins((i-2)*(m-1)*2+j*2,T,o);
      else
      ins((i-2)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2-1,o);
     }
    for(int i=1;i<n;i++)
      for(int j=1;j<=m;j++)
      {
       int o;
       scanf("%d",&o);
       if(j==1)
       ins((i-1)*(m-1)*2+j*2,T,o);
       else if (j==m)
       ins(S,(i-1)*(m-1)*2+(j-1)*2-1,o);
       else
       ins((i-1)*(m-1)*2+(j-1)*2-1,(i-1)*(m-1)*2+j*2,o);
      }
    for(int i=1;i<n;i++)
      for(int j=1;j<m;j++)
      {
       int o;
       scanf("%d",&o);
       ins((i-1)*(m-1)*2+j*2-1,(i-1)*(m-1)*2+j*2,o);   
      }
    for(int i=1;i<=T;i++){s[i]=999999999;v[i]=false;}
    s[S]=0;
    v[S]=true;
    t[1]=S;
    int st=1,ed=2;
    while(st!=ed)
    {
        int x=t[st];
        for(int i=first[x];i!=-1;i=q[i].next)
        {
         int y=q[i].y;
         if(s[x]+q[i].z<s[y])
         {
          s[y]=s[x]+q[i].z;
          if(v[y]==false)
          {
           v[y]=true;  
           t[ed]=y;
           ed++;
           if(ed>T+1)ed=1;
          }
         }
        }
        v[x]=false;
        st++;
        if(st>T+1)st=1;
    }
    printf("%d\n",s[T]);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值