[BJOI2006]狼抓兔子
思路:
求网格图的最小割。然而网格图的边数比较多,直接用EdmondsKarp算法会TLE(据说用Dinic或ISAP可以过),解决的方法是将网格图的最小割转化成其对偶图的最短路,设图的左下端为起点,右上端为重点,然后跑一遍Dijkstra即可。
注意要特判$n=1$或$m=1$的情况,另外因为每个方格实际上是会被斜线分成两个三角,所以点数要开两倍$n^2$,也就是$2\times10^6$。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 #include<functional> 5 #include<ext/pb_ds/priority_queue.hpp> 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int inf=0x7fffffff; 14 struct Edge { 15 int to,w; 16 }; 17 const int V=2000002; 18 std::vector<Edge> e[V]; 19 inline void add_edge(const int u,const int v,const int w) { 20 e[u].push_back((Edge){v,w}); 21 } 22 int s,t; 23 struct Vertex { 24 int id,d; 25 bool operator > (const Vertex &x) const { 26 return d>x.d; 27 } 28 }; 29 int d[V]; 30 bool v[V]={0}; 31 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 32 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[V]; 33 inline void Dijkstra() { 34 p[s]=q.push((Vertex){s,d[s]=0}); 35 for(int i=1;i<=t;i++) p[i]=q.push((Vertex){i,d[i]=inf}); 36 while(q.top().d!=inf) { 37 Vertex x=q.top(); 38 for(unsigned i=0;i<e[x.id].size();i++) { 39 Edge &y=e[x.id][i]; 40 if(v[y.to]) continue; 41 if(d[x.id]+y.w<d[y.to]) { 42 q.modify(p[y.to],(Vertex){y.to,d[y.to]=d[x.id]+y.w}); 43 } 44 } 45 q.modify(p[x.id],(Vertex){x.id,inf}); 46 v[x.id]=true; 47 } 48 } 49 int main() { 50 int n=getint(),m=getint(); 51 if(n==1&&m==1) { 52 puts("0"); 53 return 0; 54 } 55 if(n==1) { 56 int ans=inf; 57 for(int i=1;i<m;i++) { 58 ans=std::min(ans,getint()); 59 } 60 printf("%d\n",ans); 61 return 0; 62 } 63 if(m==1) { 64 int ans=inf; 65 for(int i=1;i<n;i++) { 66 ans=std::min(ans,getint()); 67 } 68 printf("%d\n",ans); 69 return 0; 70 } 71 s=0,t=(n-1)*(m-1)*2+1; 72 for(int j=1;j<m;j++) { 73 int w=getint(); 74 add_edge(t,j*2-1,w); 75 add_edge(j*2-1,t,w); 76 } 77 for(int i=2;i<n;i++) { 78 for(int j=1;j<m;j++) { 79 int w=getint(); 80 add_edge((i-1)*(m-1)*2+j*2-1,(i-2)*(m-1)*2+j*2,w); 81 add_edge((i-2)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2-1,w); 82 } 83 } 84 for(int j=1;j<m;j++) { 85 int w=getint(); 86 add_edge(s,(n-2)*(m-1)*2+j*2,w); 87 add_edge((n-2)*(m-1)*2+j*2,s,w); 88 } 89 for(int i=1;i<n;i++) { 90 int w=getint(); 91 add_edge(s,(i-1)*(m-1)*2+2,w); 92 add_edge((i-1)*(m-1)*2+2,s,w); 93 for(int j=2;j<m;j++) { 94 w=getint(); 95 add_edge((i-1)*(m-1)*2+j*2,(i-1)*(m-1)*2+(j-1)*2-1,w); 96 add_edge((i-1)*(m-1)*2+(j-1)*2-1,(i-1)*(m-1)*2+j*2,w); 97 } 98 w=getint(); 99 add_edge(i*(m-1)*2-1,t,w); 100 add_edge(t,i*(m-1)*2-1,w); 101 } 102 for(int i=1;i<n;i++) { 103 for(int j=1;j<m;j++) { 104 int w=getint(); 105 add_edge((i-1)*(m-1)*2+j*2-1,(i-1)*(m-1)*2+j*2,w); 106 add_edge((i-1)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2-1,w); 107 } 108 } 109 Dijkstra(); 110 printf("%d\n",d[t]); 111 return 0; 112 }