BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 23822 Solved: 6012
[Submit][Status][Discuss]
Description
Input
Output
输出一个整数,表示参与伏击的狼的最小数量.
Sample Input
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
Sample Output
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
Source
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001
分析:最大流写法如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n,m; 5 inline int read() 6 { 7 int x=0,f=1; 8 char ch=getchar(); 9 while(ch<'0'||ch>'9') 10 { 11 if(ch=='-') 12 f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') 16 { 17 x=x*10+ch-'0'; 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 inline void write(int x) 23 { 24 if(x<0) 25 { 26 putchar('-'); 27 x=-x; 28 } 29 if(x>9) 30 { 31 write(x/10); 32 } 33 putchar(x%10+'0'); 34 } 35 int ne; 36 const int N=1000010; 37 struct data 38 { 39 int to,next,v; 40 }e[N<<3]; 41 int head[N]; 42 int h[N],q[N],ans; 43 inline void update(int u,int v,int w) 44 { 45 ne++; 46 e[ne].to=v; 47 e[ne].v=w; 48 e[ne].next=head[u]; 49 head[u]=ne; 50 } 51 inline bool BFS() 52 { 53 int now,i; 54 memset(h,-1,sizeof(h)); 55 int t=0,w=1; 56 q[t]=1; 57 h[1]=0; 58 while(t<w) 59 { 60 now=q[t]; 61 t++; 62 i=head[now]; 63 while(i) 64 { 65 if(e[i].v&&h[e[i].to]<0) 66 { 67 q[w++]=e[i].to; 68 h[e[i].to]=h[now]+1; 69 } 70 i=e[i].next; 71 } 72 } 73 if(h[n*m]==-1) 74 return false; 75 return true; 76 } 77 inline int DFS(int x,int f) 78 { 79 if(x==n*m) 80 return f; 81 int i=head[x]; 82 int w,used=0; 83 while(i) 84 { 85 if(e[i].v&&h[e[i].to]==h[x]+1) 86 { 87 w=f-used; 88 w=DFS(e[i].to,min(w,e[i].v)); 89 e[i].v-=w; 90 e[i+1].v+=w; 91 used+=w; 92 if(used==f) 93 return f; 94 } 95 i=e[i].next; 96 } 97 if(!used) 98 h[x]=-1; 99 return used; 100 } 101 inline void dinic() 102 { 103 while(BFS()) 104 { 105 ans+=DFS(1,0x7f7f7f7f); 106 } 107 } 108 int main() 109 { 110 n=read(); 111 m=read(); 112 int x; 113 for(int i=1;i<=n;i++) 114 { 115 for(int j=1;j<m;j++) 116 { 117 x=read(); 118 update(m*(i-1)+j,m*(i-1)+j+1,x); 119 update(m*(i-1)+j+1,m*(i-1)+j,x); 120 } 121 } 122 for(int i=1;i<n;i++) 123 { 124 for(int j=1;j<=m;j++) 125 { 126 x=read(); 127 update(m*(i-1)+j,m*(i)+j,x); 128 update(m*(i)+j,m*(i-1)+j,x); 129 } 130 } 131 for(int i=1;i<n;i++) 132 { 133 for(int j=1;j<m;j++) 134 { 135 x=read(); 136 update(m*(i-1)+j,m*(i)+j+1,x); 137 update(m*(i)+j+1,m*(i-1)+j,x); 138 } 139 } 140 dinic(); 141 write(ans); 142 return 0; 143 }
分析:最小割,上网看了别人的博客,学习到了s-t平面图的最小割的解法,把原图中的面看作点,起点和终点都等同于最外面的那一个面,原图中一条边权值为w,新图中就等同于此边在平面图中分割开的两个面(即新图中两个点)连一条边,权值为w。建模完成后,新图中的起点和终点的一条路径就穿插过原图的一些边,即一条路径等于原图中的一个割,所以最小割就等于新图的最短路径长度。确实很厉害。
下面给出SPFA+最小割代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 inline int read() 5 { 6 int x=0,f=1; 7 char ch=getchar(); 8 while(ch<'0'||ch>'9') 9 { 10 if(ch=='-') 11 f=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9') 15 { 16 x=x*10+ch-'0'; 17 ch=getchar(); 18 } 19 return x*f; 20 } 21 inline void write(int x) 22 { 23 if(x<0) 24 { 25 putchar('-'); 26 x=-x; 27 } 28 if(x>9) 29 { 30 write(x/10); 31 } 32 putchar(x%10+'0'); 33 } 34 #define M 2000001 35 int n,m,nm; 36 struct data 37 { 38 int to,next,v; 39 }e[4*M]; 40 int dis[M],q[M],head[M]; 41 bool flag[M]; 42 int ne; 43 inline void update(int u,int v,int w) 44 { 45 ne++; 46 e[ne].to=v; 47 e[ne].v=w; 48 e[ne].next=head[u]; 49 head[u]=ne; 50 ne++; 51 e[ne].to=u; 52 e[ne].v=w; 53 e[ne].next=head[v]; 54 head[v]=ne; 55 } 56 inline void spfa() 57 { 58 memset(dis,0x3f,sizeof(dis)); 59 int i,t=0,w=1; 60 dis[0]=q[w]=0;flag[0]=1; 61 while(t!=w) 62 { 63 int u=q[t++]; 64 flag[u]=0; 65 if(t==M)t=0; 66 for(int i=head[u];i;i=e[i].next) 67 { 68 int v=e[i].to; 69 if(dis[v]>dis[u]+e[i].v) 70 { 71 dis[v]=dis[u]+e[i].v; 72 if(flag[v]==0) 73 { 74 flag[v]=1; 75 q[w++]=v; 76 if(w==M)w=0; 77 } 78 } 79 } 80 } 81 } 82 int main() 83 { 84 n=read(); 85 m=read(); 86 nm=(n*m-m-n+1)<<1; 87 int x; 88 for(int j=1;j<m;j++) 89 { 90 x=read(); 91 update(j,nm+1,x); 92 } 93 for(int i=1;i<n-1;i++) 94 { 95 for(int j=1;j<m;j++) 96 { 97 x=read(); 98 update((i<<1)*(m-1)+j,((i<<1)-1)*(m-1)+j,x); 99 } 100 } 101 for(int j=1;j<m;j++) 102 { 103 x=read(); 104 update(0,((n<<1)-3)*(m-1)+j,x); 105 } 106 for(int i=0;i<n-1;i++) 107 { 108 for(int j=1;j<=m;j++) 109 { 110 x=read(); 111 if(j==1) 112 update(0,(i<<1)*(m-1)+m,x); 113 else if(j==m) 114 update((i<<1|1)*(m-1),nm+1,x); 115 else 116 update((i<<1)*(m-1)+j-1,(i<<1)*(m-1)+j+m-1,x); 117 } 118 } 119 for(int i=0;i<n-1;i++) 120 { 121 for(int j=1;j<m;j++) 122 { 123 x=read(); 124 update((i<<1|1)*(m-1)+j,(i<<1)*(m-1)+j,x); 125 } 126 } 127 spfa(); 128 write(dis[nm+1]); 129 return 0; 130 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。