[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 }

 

posted @ 2017-08-09 08:24  skylee03  阅读(164)  评论(0编辑  收藏  举报