BZOJ 1001 [BeiJing2006]狼抓兔子 平面图最大流

Description

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Solutions

一眼最小割,写个好一点的网络流随意暴力跑一下可以切,然而还有更好的做法

  1 #include<map>
  2 #include<cmath>
  3 #include<ctime>
  4 #include<queue>
  5 #include<stack>
  6 #include<cstdio>
  7 #include<climits>
  8 #include<iomanip>
  9 #include<cstring>
 10 #include<cstdlib>
 11 #include<iostream>
 12 #include<algorithm>
 13
 14 #define maxn 1000000+5
 15 #define maxs 6000000+5
 16 #define set(a,b) memset(a,(b),sizeof(a))
 17 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++)
 18 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--)
 19 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next)
 20 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next)
 21
 22 using namespace std;
 23
 24 typedef long long ll;
 25
 26 struct sides{
 27   int u,v,c;
 28   int next;
 29 }s[maxs];
 30
 31
 32 queue<int> q;
 33
 34 int h[maxn];
 35 int first[maxn],cur[maxn];
 36 int ind=0;
 37 int ans=0;
 38 int n,m;
 39
 40 void add_f(int u,int v,int c){
 41   s[ind].u=u,s[ind].v=v,s[ind].c=c;
 42   s[ind].next=first[u],first[u]=ind;
 43   ind++;
 44   s[ind].u=v,s[ind].v=u,s[ind].c=c;
 45   s[ind].next=first[v],first[v]=ind;
 46   ind++;
 47 }
 48
 49 void read()
 50 {
 51 #ifndef ONLINE_JUDGE
 52   freopen("1001.in","r",stdin);
 53   freopen("1001.out","w",stdout);
 54 #endif
 55
 56   int c;
 57   cin >> n >> m ;
 58   set(first,-1);
 59   fr(i,1,n)
 60     fr(j,1,m-1){
 61       cin >> c ;
 62        add_f(m*(i-1)+j,m*(i-1)+j+1,c);
 63   }
 64   fr(i,1,n-1)
 65     fr(j,1,m){
 66       cin >> c ;
 67        add_f(m*(i-1)+j,m*(i)+j,c);
 68   }
 69   fr(i,1,n-1)
 70     fr(j,1,m-1){
 71       cin >> c ;
 72        add_f(m*(i-1)+j,m*(i)+j+1,c);
 73   }
 74 }
 75
 76 void write()
 77 {
 78   cout << ans ;
 79 }
 80
 81 bool bfs(int u)
 82 {
 83   set(h,-1);
 84   h[u]=1;
 85   q.push(u);
 86   while( !q.empty() ){
 87     int u=q.front();q.pop();
 88     fe(i,-1,u)
 89       if( s[i].c && h[s[i].v]==-1 ){
 90     h[s[i].v]=h[u]+1;
 91     q.push(s[i].v);
 92       }
 93   }
 94   return h[n*m]!=-1;
 95 }
 96
 97 int dfs(int u,int flow)
 98 {
 99   if( u==n*m ) return flow;
100   int w,used=0;
101   fec(i,-1,u){
102     if( h[s[i].v]==h[u]+1 && s[i].c ){
103       w=dfs(s[i].v,min(flow-used,s[i].c));
104       s[i].c-=w,s[i^1].c+=w;
105       used+=w;
106       if( used==flow ) return flow;
107     }
108   }
109   if( !used ) h[u]=-1;
110   return used;
111 }
112
113 void dinic()
114 {
115   while( bfs(1) ){
116     fr(i,1,n*m)
117       cur[i]=first[i];
118     ans+=dfs(1,INT_MAX);
119   }
120 }
121
122 void work()
123 {
124   dinic();
125 }
126
127 int main()
128 {
129   read();
130   work();
131   write();
132   return 0;
133 }

然后去学习了以下平面图

简单地,对于任意一个图 G,我们有它的对偶图 G’,即将原图的点与边划分成的平面视作新图 G’ 中的点,反之亦然

新图中的边就是原图相邻两平面,边权是连接这两个平面所割的边

于是 G’ 中的环对应 G 中的割一一对应

然后我们对于新图再连接一下原源点和原汇点,形成一个新的平面,我们将这个平面视作新源点S,无穷大的平面视作新汇点T,然后再把对偶图中S到T直接相连的边删掉

可以知道求原图的最大流就相当于求新图的最短路

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

然后就划分平面= =,事实上根本分不清……最后膜了黄学长代码才过的= =

  1 #include<map>
  2 #include<cmath>
  3 #include<ctime>
  4 #include<queue>
  5 #include<stack>
  6 #include<cstdio>
  7 #include<climits>
  8 #include<iomanip>
  9 #include<cstring>
 10 #include<cstdlib>
 11 #include<iostream>
 12 #include<algorithm>
 13
 14 #define maxn 2000000+5
 15 #define maxs 8000000+5
 16 #define set(a,b) memset(a,(b),sizeof(a))
 17 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++)
 18 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--)
 19 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next)
 20 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next)
 21
 22 using namespace std;
 23
 24 typedef long long ll;
 25 typedef pair<int,int> pii;
 26
 27 struct sides{
 28   int u,v,w;
 29   int next;
 30 }s[maxs];
 31
 32 queue<int> q;
 33 priority_queue<pii,vector<pii>,greater<pii> > q;
 34
 35 int dis[maxn],inq[maxn];
 36 int first[maxn],ind=0;
 37 int n,m,num;
 38
 39 void add_s(int u,int v,int w){
 40   s[ind].u=u,s[ind].v=v,s[ind].w=w;
 41   s[ind].next=first[u],first[u]=ind;
 42   ind++;
 43   s[ind].u=v,s[ind].v=u,s[ind].w=w;
 44   s[ind].next=first[v],first[v]=ind;
 45   ind++;
 46 }
 47
 48 void read()
 49 {
 50 #ifndef ONLINE_JUDGE
 51   freopen("1001.in","r",stdin);
 52   freopen("1001.out","w",stdout);
 53 #endif
 54
 55   int c;
 56   set(first,-1);
 57   cin >> n >> m ;
 58   num=(n-1)*(m-1)<<1;
 59   fr(i,1,m-1){
 60     cin >> c ;
 61     add_s(i,num+1,c);
 62   }
 63   fr(i,1,n-2)
 64     fr(j,1,m-1){
 65       cin >> c ;
 66       add_s((i<<1)*(m-1)+j,((i<<1)-1)*(m-1)+j,c);
 67   }
 68   fr(i,1,m-1){
 69     cin >> c ;
 70     add_s(0,((n<<1)-3)*(m-1)+i,c);
 71   }
 72   fr(i,0,n-2)
 73     fr(j,1,m){
 74     cin >> c ;
 75     if( j==1 )
 76       add_s(0,(i<<1)*(m-1)+m,c);
 77     else if( j==m )
 78       add_s((i<<1|1)*(m-1),num+1,c);
 79     else
 80       add_s((i<<1)*(m-1)+j-1,(i<<1)*(m-1)+j+m-1,c);
 81   }
 82   fr(i,0,n-1)
 83     fr(j,1,m-1){
 84       cin >> c ;
 85       add_s((i<<1|1)*(m-1)+j,(i<<1)*(m-1)+j,c);
 86   }
 87 }
 88
 89 void write()
 90 {
 91   cout << dis[num+1] ;
 92 }
 93
 94 void SPFA()
 95 {
 96   set(dis,127);
 97   q.push(0);
 98   dis[0]=0;
 99   while( !q.empty() ){
100     int u=q.front();q.pop();
101     inq[u]=0;
102     fe(i,-1,u)
103       if( dis[s[i].v]>dis[u]+s[i].w ){
104     dis[s[i].v]=dis[u]+s[i].w;
105     if( !inq[s[i].v] )
106       q.push(s[i].v);
107       }
108   }
109 }
110
111 void dijkstra()
112 {
113   set(dis,127);
114   q.push(make_pair(0,0));
115   dis[0]=0;
116   while( !q.empty() ){
117     pii st=q.top();q.pop();
118     int sd=st.second;
119     if( inq[sd] ) continue;
120     inq[sd]=1;
121     fe(i,-1,sd)
122       if( dis[s[i].v]>dis[sd]+s[i].w ){
123     dis[s[i].v]=dis[sd]+s[i].w;
124     q.push(make_pair(dis[s[i].v],s[i].v));
125       }
126   }
127 }
128
129 void work()
130 {
131   SPFA();
132   dijkstra();
133 }
134
135 int main()
136 {
137   read();
138   work();
139   write();
140   return 0;
141 }

//Dijkstra好像比SPFA快一点

然后= =

我就

淡疼地发现

平面图比我的暴力慢 Orz  = =

时间: 2024-07-29 03:25:10

BZOJ 1001 [BeiJing2006]狼抓兔子 平面图最大流的相关文章

BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 23822  Solved: 6012[Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M

bzoj 1001: [BeiJing2006]狼抓兔子 平面图最小割

平面图跑最大流 可以转换为其对偶图跑最短路 一个环对应一个割  找到最小环(即最短路)极为所求,注意辅助边的建立 加入读入优化  不过时间还是一般  估计是dij写的不好   大神勿喷~~~ /************************************************************** Problem: 1001 User: 96655 Language: C++ Result: Accepted Time:1724 ms Memory:95120 kb ****

BZOJ 1001: [BeiJing2006]狼抓兔子 对偶图

本题是最大流转最小割转对偶图最短路 推荐周东的<浅析最大最小定理在信息学竞赛中的应用> 1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 12166  Solved: 2866 [Submit][Status][Discuss] Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在

BZOJ 1001: [BeiJing2006]狼抓兔子(最短路)

平面图的最小割转化为对偶图的最短路(资料:两极相通——浅析最大最小定理在信息学竞赛中的应用) ,然后DIJKSTRA就OK了. ------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<que

BZOJ 1001: [BeiJing2006]狼抓兔子 最小割

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)

BZOJ 1001 [BeiJing2006]狼抓兔子

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 题意: ... 很容易想到求的是一个最小割=最大流. 之前一直用的刘汝佳的模板STL过题,很久没用过数组模拟了. 再次熟悉一下写法,first数组是索引数组,标记的结点的最后一条边,利用next数组找到上一条边. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1100000 6 int n,m,

bzoj 1001: [BeiJing2006]狼抓兔子 最短路+对偶图

题意:求一个表格图的最小割. 分析:这题如果套上一个网络流的话是会挂的,所以我们要把该图转换成它的对偶图,具体方法可以参照两级相通----浅析最大最小定理在信息学竞赛中的应用 By 周冬.然后跑对短路就好了. 良心的出题人居然没卡spfa 这题要特判n=1 or m=1的情况 这次一开始无限12msWA的原因是spfa的结束条件是until head>=tail,而我用的是循环队列--不想多说,以后一定要注意才行啊. 代码: const maxn=2000009; var s,t,n,m,e:l

bzoj 1001 [BeiJing2006]狼抓兔子 最小割+最短路

题面 题目传送门 解法 将最大流转化成最小割,然后跑最短路即可 具体如何见图可以参考下图 尽量用dijkstra 代码 #include <bits/stdc++.h> #define PI pair <int, int> #define mp make_pair #define N 1010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x

【BZOJ】1001: [BeiJing2006]狼抓兔子

1001: [BeiJing2006]狼抓兔子 Description 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下 三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下角(N,M)的窝中去,狼王开始伏击