BZOJ1001狼抓兔子
2017-12-30 11:12
302 查看
昨天在BZOJ上看到了一道题,就是问题集的第二道 BZOJ1001
题目描述是这样的:
当时第一眼看过去就知道这道题是求最小割的问题,但是怎么样求出最小割?
去网上直接搜这道题的解析,发现有一种解法很巧妙,就是求出这张图的对偶图,是在输入数据的时候就直接根据循环的层数建出对偶图了(这里的对偶图做了一下处理,要连接start和end)
然后对对偶图做djkstra算法,以建的对偶图中的s*和t* 中的某一点为起点,找出最小最优路径,便是最小割这里贴出一份一位同学的代码
这个同学建图的方法很简单灵活,我记得大二的时候我数据结构课程的助教就是这样建图的,首先建一个边集,一个head数组,head
代表编号为n的点的第一个边在边集中的位置,边集中存储了所有的边,边结构体中用到的next就是指针指向下一条边在边集中的位置。
读数据的时候先是读横向的边
这个时候如果是第一行的话,起点就是s*,如果是最后一行,起点就是t* 其余的根据i和j的值计算出位置
而后就是用djkstra算法求出最终结果。
题目描述是这样的:
当时第一眼看过去就知道这道题是求最小割的问题,但是怎么样求出最小割?
去网上直接搜这道题的解析,发现有一种解法很巧妙,就是求出这张图的对偶图,是在输入数据的时候就直接根据循环的层数建出对偶图了(这里的对偶图做了一下处理,要连接start和end)
然后对对偶图做djkstra算法,以建的对偶图中的s*和t* 中的某一点为起点,找出最小最优路径,便是最小割这里贴出一份一位同学的代码
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define inf 0x7fffffff using namespace std; const int maxn=2000000+10; const int M = maxn*3+10; int n,m,nn,mm; int from,to; struct Edge { int v,flow; int next; }edge[M]; int head[maxn],edgenum; void add(int u,int v,int flow) { edge[edgenum].v=v ;edge[edgenum].flow=flow ; edge[edgenum].next=head[u] ;head[u]=edgenum++ ; edge[edgenum].v=u ;edge[edgenum].flow=flow ; edge[edgenum].next=head[v] ;head[v]=edgenum++ ; } struct node { int v,w; friend bool operator < (node a,node b) { return a.w > b.w; } }cur,tail; int d[maxn],vis[maxn]; void Dijkstra(int from,int to) { for (int i=0 ;i<maxn ;i++) d[i]=inf; memset(vis,0,sizeof(vis)); d[from]=0; priority_queue<node> Q; cur.v=from ;cur.w=0 ; Q.push(cur); while (!Q.empty()) { cur=Q.top() ;Q.pop() ; int x=cur.v; if (vis[x]) continue; vis[x]=1; for (int i=head[x] ;i!=-1 ;i=edge[i].next) { if (d[edge[i].v ]>d[x]+edge[i].flow) { d[edge[i].v ]=d[x]+edge[i].flow; tail.v=edge[i].v; tail.w=d[edge[i].v ]; Q.push(tail); } } } printf("%d\n",d[to]); } int main() { while (scanf("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head)); edgenum=0; from=0; to=2*(n-1)*(m-1)+1; int x,y,cost; for (int i=1 ;i<=n ;i++) { for (int j=1 ;j<m ;j++) { scanf("%d",&cost); x= i==1 ? from : (2*(i-1)-1)*(m-1)+j; y= i==n ? to : (2*(i-1))*(m-1)+j; add(x,y,cost); } } for (int i=1 ;i<n ;i++) { for (int j=1 ;j<=m ;j++) { scanf("%d",&cost); x= j==1 ? to : (2*(i-1))*(m-1)+j-1; y= j==m ? from : (2*(i-1))*(m-1)+j-1+m; add(x,y,cost); } } for (int i=1 ;i<n ;i++) { for (int j=1 ;j<m ;j++) { scanf("%d",&cost); x=(2*(i-1))*(m-1)+j; y=(2*(i-1)+1)*(m-1)+j; add(x,y,cost); } } Dijkstra(from,to); } return 0; }
这个同学建图的方法很简单灵活,我记得大二的时候我数据结构课程的助教就是这样建图的,首先建一个边集,一个head数组,head
代表编号为n的点的第一个边在边集中的位置,边集中存储了所有的边,边结构体中用到的next就是指针指向下一条边在边集中的位置。
读数据的时候先是读横向的边
这个时候如果是第一行的话,起点就是s*,如果是最后一行,起点就是t* 其余的根据i和j的值计算出位置
而后就是用djkstra算法求出最终结果。
相关文章推荐
- AC日记——狼抓兔子 bzoj 1001
- [最小割+对偶建图+最短路] BZOJ1001: [BeiJing2006]狼抓兔子
- 【BZOJ 1001】狼抓兔子 对偶图+SPFA
- BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA
- 【bzoj 1001】狼抓兔子(最小割)
- bzoj 1001: [BeiJing2006]狼抓兔子
- [BZOJ1001]-狼抓兔子 Dinic模板题
- bzoj 1001 狼抓兔子 平面图最小割
- 【最短路】BZOJ1001狼抓兔子
- BZOJ1001: [BeiJing2006]狼抓兔子
- BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA
- 平面圖最小割 BZOJ1001: [BeiJing2006]狼抓兔子 BZOJ 2007: [Noi2010]海拔
- bzoj1001【BeiJing2006】狼抓兔子
- bzoj1001狼抓兔子——网络流平面图问题
- 【BZOJ1001】[BeiJing2006]狼抓兔子【最小割】【最短路】【对偶图】
- [bzoj1001][BeiJing2006]狼抓兔子
- BZOJ 1001 狼抓兔子 (网络流最小割/平面图的对偶图的最短路)
- bzoj 1001: [BeiJing2006]狼抓兔子
- BZOJ 1001: [BeiJing2006]狼抓兔子
- BZOJ 1001: 狼抓兔子