bzoj1001

spfa--周冬《两极相通——浅析最大—最小定理在信息学竞赛中的应用》

虽然是网络流最小割,但是我们可以转换一下,转成最短路

简单点讲,每个平面图都对应一个对偶图,对偶图中的最小环就是原图的最小割,如果删去对偶图中s-t这条边,就是相当于求最短路了!

建图十分玄学,建完后跑一遍spfa就好了。

#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
const int inf=2147483647;
const int maxn=2000010;
struct hh
{
  int u,v,w,next;
}e[maxn*3];
int n,m,point;
int head[maxn],dis[maxn],vis[maxn];
template <class T> void read(T&x)
{
  x=0;char c=getchar();int f=0; 
  while(c<'0'||c>'9'){f|=(c=='-');c=getchar();}
  while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
  x=f?-x:x;
}
void spfa(int s)
{
  queue<int>q;
  memset(dis,0x7f/2,sizeof(dis));
  memset(vis,0,sizeof(vis));
  dis[s]=0;q.push(s);vis[s]=1;
  while(!q.empty())
  {
      int x=q.front();q.pop();vis[x]=0;
      for(int i=head[x];i!=-1;i=e[i].next)
      {
        int y=e[i].v;
        if(dis[y]>dis[x]+e[i].w)
        {
            dis[y]=dis[x]+e[i].w;
        if(!vis[y])
        {
          q.push(y);
          vis[y]=1;
        }
        }
      }
  }
  return;
}
void add(int u,int v,int w)
{
  e[++point].u=u;e[point].v=v;e[point].w=w;e[point].next=head[u];head[u]=point;
  e[++point].u=v;e[point].v=u;e[point].w=w;e[point].next=head[v];head[v]=point;
}
int main()
{
  memset(head,-1,sizeof(head));
  read(n);read(m);
  if (n == 1 || m == 1)
    {
        if (n > m) swap(n, m);
        int ans = inf;
        for (int i = 1; i < m; ++i)
        {
            int x;
            read(x);
            if (x < ans) ans = x;
        }
        printf("%d\n", ans);
        exit(0);
    }
    int S=0,T=2*(m-1)*(n-1)+1;
    int w;
    for(int j=1;j<m;j++)
    {
        int id=j*2-1;
        read(w);
        add(S,id,w);
    }
    for(int i=1;i<n-1;i++)
    {
        for(int j=1;j<m;j++)
        {
            int t1=2*((i-1)*(m-1)+j);
            int t2=2*(i*(m-1)+j)-1;
            read(w);
            add(t1,t2,w);
        }
    }
    for(int j=1;j<m;j++)
    {
        int id=2*((n-2)*(m-1)+j);
        read(w);
        add(id,T,w);
    }
    //横向边
    
    for(int i=0;i<n-1;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&w);
            if(j==1)//与终点相连 
            {
                int id=2*(i*(m-1)+j);
                add(id,T,w);
            }
            else if(j==m)
            {
                int id=2*((i+1)*(m-1))-1;
                add(S,id,w); 
            }
            else
            {
                int t1=2*(i*(m-1)+j-1)-1;
                int t2=2*(i*(m-1)+j);
                add(t1,t2,w);
            }
        }
    } 
    //纵向
    
    for(int i=0;i<n-1;i++)
    {
        for(int j=1;j<m;j++)
        {
            read(w);
            int t1=2*(i*(m-1)+j)-1;
            int t2=2*(i*(m-1)+j);
            add(t1,t2,w);
        }
    } 
    //斜向
    spfa(0);
    printf("%d",dis[T]);
    return 0;
}
View Code

 

posted @ 2017-10-23 17:28  新手-周  阅读(171)  评论(0编辑  收藏  举报