【解题思路】

  显然,这题的答案是这个网格图的最小割。根据最大流-最小割定理,我们可以用网络流算法来求其最小割,时间复杂度最小为O(V2√E)。

  特殊的,这个网格图是一个平面图,于是可以根据平面图最小割-最短路定理,转化为其对偶图的最短路,时间复杂度最小为O(kE)或O(Vlog2V)(民科算法spfa前途不可估量)。

【参考代码】

  恩,听说这题我当初RE得生活不能自理,于是直接贴了orz::hzwer大神的代码。。

  贴个T掉的SAP板子。。(已修正了假板子的当前弧优化。。但还是T得生活不能自理。。)

  1 #pragma GCC optimize(2)
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <functional>
  5 #define REP(i,low,high) for(register int i=(low);i<=(high);++i)
  6 #define INF (0x7f7f7f7f)
  7 #define function(type) __attribute__((optimize("-O2"))) inline type
  8 #define procedure __attribute__((optimize("-O2"))) inline void
  9 using namespace std;
 10 
 11 //ex_cmp {
 12 template<typename T,class Compare>
 13 inline bool getcmp(T&target,const T&pattern,Compare comp)
 14 {
 15     return comp(pattern,target)?target=pattern,1:0;
 16 }
 17 //} ex_cmp
 18 
 19 //quick_io {
 20 #include <cctype>
 21 #include <cstdio>
 22 function(int) getint()
 23 {
 24     char c=getchar(); for(;!isdigit(c)&&c!='-';c=getchar());
 25     short s=1; for(;c=='-';c=getchar()) s*=-1; int r=0;
 26     for(;isdigit(c);c=getchar()) r=(r<<3)+(r<<1)+c-'0';
 27     return s*r;
 28 }
 29 //} quick_io
 30 
 31 static const int N=1000000,M=3000000; static int cardE=0;
 32 
 33 struct edge
 34 {
 35     int fr,to,cap;
 36     edge(const int&f=0,const int&t=0,const int&c=0)
 37     :fr(f),to(t),cap(c) {}
 38 }edg[(M<<1)+5];
 39 
 40 int hed[N+5],nxt[(M<<1)+5],hsh[1005][1005];
 41 
 42 procedure add_edge(const int&fr,const int&to,const int&cp)
 43 {
 44     edg[cardE]=edge(fr,to,cp),nxt[cardE]=hed[fr],hed[fr]=cardE++;
 45 }
 46 
 47 //SAP {
 48 int aug[N+5],cur[N+5],dis[N+5],gap[N+5],path[N+5];
 49 
 50 function(int) augment(const int&S,const int&T)
 51 {
 52     for(register int i=T;i!=S;i=edg[path[i]].fr)
 53     {
 54         edg[path[i]].cap-=aug[T],edg[path[i]^1].cap+=aug[T];
 55     }
 56     return aug[T];
 57 }
 58 
 59 function(int) SAP(const int&S,const int&T,const int&N)
 60 {
 61     memset(aug,0,sizeof aug),memset(gap,0,sizeof gap);
 62     memset(dis,0,sizeof dis); REP(i,1,N) cur[i]=hed[i];
 63     aug[S]=INF,gap[0]=N; int ret=0;
 64     for(register int fr=S;dis[S]<N;)
 65     {
 66         if(fr==T) ret+=augment(fr=S,T); bool flag=1;
 67         for(register int i=cur[fr];~i;i=nxt[i])
 68         {
 69             int to=edg[i].to;
 70             if(edg[i].cap&&dis[fr]==dis[to]+1)
 71             {
 72                 aug[to]=min(aug[fr],edg[i].cap)
 73                 ,path[to]=cur[fr]=i,fr=to,flag=0; break;
 74             }
 75         }
 76         if(flag)
 77         {
 78             if(!--gap[dis[fr]]) break; dis[fr]=N;
 79             for(register int i=hed[fr];~i;i=nxt[i])
 80             if(edg[i].cap)
 81             {
 82                 getcmp(dis[fr],dis[edg[i].to]+1,less<int>());
 83             }
 84             ++gap[dis[fr]],cur[fr]=hed[fr];
 85             if(fr!=S) fr=edg[path[fr]].fr;
 86         }
 87     }
 88     return ret;
 89 }
 90 //} SAP
 91 
 92 int main()
 93 {
 94     int n=getint(),m=getint(),cardP=0;
 95     REP(i,1,n) REP(j,1,m) hsh[i][j]=++cardP;
 96     memset(hed,-1,sizeof hed),memset(nxt,-1,sizeof nxt);
 97     REP(i,1,n) REP(j,2,m)
 98     {
 99         int w=getint();
100         add_edge(hsh[i][j-1],hsh[i][j],w),
101         add_edge(hsh[i][j],hsh[i][j-1],w);
102     }
103     REP(i,2,n) REP(j,1,m)
104     {
105         int w=getint();
106         add_edge(hsh[i-1][j],hsh[i][j],w),
107         add_edge(hsh[i][j],hsh[i-1][j],w);
108     }
109     REP(i,2,n) REP(j,2,m)
110     {
111         int w=getint();
112         add_edge(hsh[i-1][j-1],hsh[i][j],w),
113         add_edge(hsh[i][j],hsh[i-1][j-1],w);
114     }
115     printf("%d\n",SAP(1,cardP,cardP));
116     return 0;
117 }
View Code

  然后对偶图最短路。。(被队列长度卡了好久。。用了循环队列才过。。)

  1 #pragma GCC optimize(2)
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <functional>
  5 #define REP(i,low,high) for(register int i=(low);i<=(high);++i)
  6 #define INF (0x3f3f3f3f)
  7 #define function(type) __attribute__((optimize("-O2"))) inline type
  8 #define procedure __attribute__((optimize("-O2"))) inline void
  9 using namespace std;
 10 
 11 //ex_cmp {
 12 template<typename T,class Compare>
 13 inline bool getcmp(T&target,const T&pattern,Compare comp)
 14 {
 15     return comp(pattern,target)?target=pattern,1:0;
 16 }
 17 //} ex_cmp
 18 
 19 //quick_io {
 20 #include <cctype>
 21 #include <cstdio>
 22 function(long long) getint()
 23 {
 24     char c=getchar(); for(;!isdigit(c)&&c!='+'&&c!='-';c=getchar());
 25     short s=1; for(;c=='+'||c=='-';c=getchar()) if(c=='-') s*=-1;
 26     long long r=0; for(;isdigit(c);c=getchar()) r=(r<<3)+(r<<1)+c-'0';
 27     return s*r;
 28 }
 29 //} quick_io
 30 
 31 static const int N=2000000,M=3000000,SIZE=(N<<1)+10;
 32 
 33 struct edge
 34 {
 35     int to,cap; edge(const int&t=0,const int&c=0):to(t),cap(c) {}
 36 }edg[(M<<1)+10];
 37 
 38 static int cardE=0; int hed[N+10],nxt[(M<<1)+10];
 39 
 40 procedure add_edge(const int&fr,const int&to,const int&cp)
 41 {
 42     edg[++cardE]=edge(to,cp),nxt[cardE]=hed[fr],hed[fr]=cardE;
 43 }
 44 
 45 //SPFA {
 46 bool inq[N+10]={0}; int dis[N+10]={0},q[SIZE];
 47 
 48 function(int&) move(int&n) {return ++n==SIZE?n=0:n;}
 49 
 50 function(int) SPFA(const int&S,const int&T)
 51 {
 52     memset(dis,0x3f,sizeof dis),inq[q[dis[S]=0]=S]=1;
 53     for(register int head=-1,tail=0;head!=tail;)
 54     {
 55         int fr=q[move(head)];
 56         for(register int i=hed[fr];i;i=nxt[i])
 57         {
 58             int to=edg[i].to;
 59             if(
 60                 getcmp(dis[to],dis[fr]+edg[i].cap,less<int>())
 61                 &&!inq[to]
 62             ) inq[q[move(tail)]=to]=1;
 63         }
 64         inq[fr]=0;
 65     }
 66     return dis[T];
 67 }
 68 //} SPFA
 69  
 70 int main()
 71 {
 72     int n=getint(),m=getint(),nm=(n-1)*(m-1)<<1;
 73     if(n==1||m==1)
 74     {
 75         int ans=INF;
 76         REP(i,1,max(m,n)-1) getcmp(ans,(int)getint(),less<int>());
 77         return printf("%d\n",ans),0;
 78     }
 79     REP(i,1,m-1)
 80     {
 81         int w=getint(); add_edge(i,nm+1,w),add_edge(nm+1,i,w);
 82     }
 83     REP(i,1,n-2) REP(j,1,m-1)
 84     {
 85         int w=getint(),fr=(i<<1)*(m-1)+j,to=fr-m+1;
 86         add_edge(fr,to,w),add_edge(to,fr,w);
 87     }
 88     REP(i,1,m-1)
 89     {
 90         int w=getint(),tmp=((n<<1)-3)*(m-1)+i;
 91         add_edge(0,tmp,w),add_edge(tmp,0,w);
 92     }
 93     REP(i,0,n-2)
 94     {
 95         int w=getint(),tmp=(i<<1)*(m-1)+m;
 96         add_edge(0,tmp,w),add_edge(tmp,0,w);
 97         REP(j,2,m-1)
 98         {
 99             int fr=(i<<1)*(m-1)+j-1,to=fr+m;
100             add_edge(fr,to,w=getint()),add_edge(to,fr,w);
101         }
102         tmp=(m-1)*(i<<1|1),w=getint(),
103         add_edge(tmp,nm+1,w),add_edge(nm+1,tmp,w);
104     }
105     REP(i,0,n-2) REP(j,1,m-1)
106     {
107         int w=getint(),fr=(i<<1)*(m-1)+j,to=fr+m-1;
108         add_edge(fr,to,w),add_edge(to,fr,w);
109     }
110     printf("%d\n",SPFA(0,nm+1));
111     return 0;
112 }
View Code