标签:bit str center led 最小 兔子 sample upd 文章
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MB
Submit: 23822 Solved: 6012
[Submit][Status][Discuss]
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只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.
Input
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M
Output
Sample Input
3 4
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
14
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 }
BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】
标签:bit str center led 最小 兔子 sample upd 文章
原文地址:http://www.cnblogs.com/ECJTUACM-873284962/p/7412829.html