UVa 563 Crimewave (网络流构图+最大流+挺好的+双向边)
2015-08-08 21:47
525 查看
题意:有一个n × m的网点状街区,在这个n × m的街区上,有l家银行。有一伙劫匪要去抢银行,抢完以后要跑,他们逃跑的路线不能重叠,逃出n × m的街区边界才算是逃跑成功。给出街区大小和各银行位置,问是否可以全部成功逃脱。
参考:http://www.cnblogs.com/scau20110726/archive/2012/12/20/2827177.html
算法思路:对于给定的网格,行为S列为A,我们按行优先给所有点标号,从1到S*A。然后对每个点拆点,拆点后一个点变为两个点(那么总点数为2*S*A),在这里我把拆点后的两个点叫做“前点”和“后点”,对于坐标为(i,j)的点,拆点后“前点”的编号为u=(i-1)*A+j , “后点”的编号好v=u+S*A;
我们还要额外设置一个源点s,编号为0,一个汇点,编号为2*S*A+1。从源点s建有向边指向所有的银行,从所有网格边沿的点建有向边指向汇点t,另外网格内一个点要和它上下左右四个点建立无向边(也就是两条有向边)。数据很大,要用邻接表保存
问题就是,我们已经事先拆点了,原来的两个点(i,j)和(i,j+1)有连线那么拆点后怎么链接呢?
第一部分(一个点和它上下左右的四个点建边):从这个点的“后点”和四周的点的“前点”建有向边(因为用邻接表建图,所以所有的有向边都有反边,注意反边的容量为0)。
第二部分(源点和所有银行建边):源点s和所有银行的“前点”建有向边(还有反边)
第三部分(所有网格边沿的点和汇点建边):所有网格边沿的点的“后点”和汇点建有向边(还有反边)
因此
第一部分:两个点a,b之间会有四边有向边,一条是a点的“后点”指向b点的“前点”,一条是b点的“后点”指向a点的“前点”。这两条还附带两条反边所以一共四条
第二部分:源点和银行的“前点”有边,再附带一个反边
第三部分:网格边沿点的“后点”和汇点有边,再附带一个反边
所有边的容量都1(这样就起到了每个点只能用一次的效果),附带的反边容量当然是为0
建图后,直接EK,算最大流,最大流等于银行个数那么可以逃脱,不等(小于)就不可以
Dinic算法:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #include <vector> #include <set> #include <climits> #include <map> #include <string> using namespace std; typedef long long ll; int s, a, b, st, ed; const int OF = 2500; //一开始是用s*a做的 const int INF = 0x3f3f3f3f; const int maxn = 5005; const int FIN = 5001; //汇点按理说s*a*2+1可以的,可这里卡BUG了 int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; struct Edge { int from,to,cap,flow; Edge(int from=0,int to=0,int cap=0,int flow=0):from(from),to(to),cap(cap),flow(flow){} }; vector<Edge> edges; vector<int> G[maxn]; int vis[maxn], d[maxn]; int cur[maxn]; void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); int m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int BFS() { memset(vis, 0, sizeof(vis)); queue<int> Q; Q.push(st); d[st] = 0; vis[st] = 1; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[u] + 1; Q.push(e.to); } } } return vis[ed]; } int DFS(int u, int a) { if (u == ed || a == 0) return a; int flow = 0, f; for (int &i = cur[u]; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[G[u][i]^1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow; } int Maxflow() { int ans = 0; while (BFS()) { memset(cur, 0, sizeof(cur)); ans += DFS(st, INF); } return ans; } int main() { int T; scanf("%d", &T); while (T--) { st = 0, ed = FIN; for (int i = 0; i <= FIN; i++) G[i].clear(); edges.clear(); scanf("%d %d %d", &s, &a, &b); for(int i=1;i<=s;i++) { for(int j=1;j<=a;j++) { AddEdge((i-1)*a+j,(i-1)*a+j+OF,1); for(int k=0;k<4;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; if((x<1)||(x>s)||(y<1)||(y>a))continue; AddEdge((i-1)*a+j+OF,(x-1)*a+y,1); } if((i==1)||(i==s)||(j==1)||(j==a))AddEdge((i-1)*a+j+OF,FIN,1); } } for(int i=0;i<b;i++) { int x,y; scanf("%d%d",&x,&y); AddEdge(0,(x-1)*a+y,1); } int ans; ans = Maxflow(); if (ans == b) printf("possible\n"); else printf("not possible\n"); } return 0; }
EK算法:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #include <vector> #include <set> #include <climits> #include <map> #include <string> using namespace std; typedef long long ll; int s, a, b, st, ed; const int OF = 2500; const int INF = 0x3f3f3f3f; const int maxn = 5005; const int FIN = 5001; int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; struct Edge { int from,to,cap,flow; Edge(int from=0,int to=0,int cap=0,int flow=0):from(from),to(to),cap(cap),flow(flow){} }; vector<Edge> edges; vector<int> G[maxn]; int vis[maxn]; int p[maxn]; void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); int m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int EK() { int f=0; for(;;) { memset(vis,0,sizeof(vis)); vis[st]=INF; queue<int> q; q.push(st); while(!q.empty()) { int u=q.front(); q.pop(); for(int v=0; v<G[u].size(); ++v) { Edge& e=edges[G[u][v]]; if(!vis[e.to]&&e.flow<e.cap) { vis[e.to]=min(vis[u],e.cap-e.flow); p[e.to]=G[u][v]; q.push(e.to); } } } if(vis[ed]==0) break; for(int u=ed; u!=st; u=edges[p[u]].from) { edges[p[u]^1].flow-=vis[ed]; edges[p[u]].flow+=vis[ed]; } f+=vis[ed]; } return f; } int main() { int T; scanf("%d", &T); while (T--) { st = 0, ed = FIN; for (int i = 0; i <= FIN; i++) G[i].clear(); edges.clear(); scanf("%d %d %d", &s, &a, &b); for(int i=1;i<=s;i++) { for(int j=1;j<=a;j++) { AddEdge((i-1)*a+j,(i-1)*a+j+OF,1); for(int k=0;k<4;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; if((x<1)||(x>s)||(y<1)||(y>a))continue; AddEdge((i-1)*a+j+OF,(x-1)*a+y,1); } if((i==1)||(i==s)||(j==1)||(j==a))AddEdge((i-1)*a+j+OF,FIN,1); } } for(int i=0;i<b;i++) { int x,y; scanf("%d%d",&x,&y); AddEdge(0,(x-1)*a+y,1); } int ans; ans = EK(); if (ans == b) printf("possible\n"); else printf("not possible\n"); } return 0; }
相关文章推荐
- 五层网络体系结构
- HDU 4940 Destroy Transportation system(上下界网络流)
- 网络编程学习总结(之client/server模型)
- 网络编程学习总结(之client/server模型)
- [转]数据中心网络虚拟化 隧道技术
- 网络信息安全攻防实验室之基础关
- Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/sc
- Java网络编程
- 【python网络编程】新浪爬虫:关键词搜索爬取微博数据
- 关于android-async-http的使用,封装网络请求
- 微信分享文本、图片(本地、二进制、网络图片)、音频、视频、Gif动态图片、网页信息--大汇总
- “TCP:三次握手”分析——以一个简单的“服务器”和“客户端”为例
- Android 网络:基于TCP协议通信,多线程,实现简单的C/S聊天室
- hdu 4807(网络流 + 贪心)
- tinyhttpd简介
- 申请https证书需要注意的4大问题
- HTTP2协议之HPACK--之头部压缩规范介绍
- https原理及tomcat配置https方法
- 企业中web服务http网站的搭建和配置
- iOS开发网络篇—NSURLConnection基本使用(一)