您的位置:首页 > 其它

BZOJ1001狼抓兔子

2017-12-30 11:12 302 查看
昨天在BZOJ上看到了一道题,就是问题集的第二道 BZOJ1001

题目描述是这样的:



当时第一眼看过去就知道这道题是求最小割的问题,但是怎么样求出最小割?

去网上直接搜这道题的解析,发现有一种解法很巧妙,就是求出这张图的对偶图,是在输入数据的时候就直接根据循环的层数建出对偶图了(这里的对偶图做了一下处理,要连接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算法求出最终结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法