您的位置:首页 > 理论基础 > 计算机网络

HDU 3376 拆点 网络流

2011-05-09 11:01 183 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3376

#include<iostream>
#include<queue>
#define N 605*605*2
#define M 605*605*10
using namespace std;
int beg,end;
struct Graph
{
struct node
{
int v,next,w,flow;
node(){};
node(int a,int b,int c,int d){
next=a;v=b;w=c;flow=d;
}
}E[M];
int head
;
bool h
;
int path
;
int dis
;
int NV,NE;
int pre
;
void init(int n)
{
NV=n;
NE=0;
memset(head,-1,sizeof(head));
}
void insert(int u,int v,int w,int flow)
{
E[NE]=node(head[u],v,w,flow);
head[u]=NE++;
E[NE]=node(head[v],u,-w,0);
head[v]=NE++;
}
bool update(int u,int v,int w)
{
if(dis[u]+w>dis[v])
{
dis[v]=dis[u]+w;
return true;
}
return false;
}
bool spfa()
{
memset(h,0,sizeof(h));
memset(pre,-1,sizeof(pre));
memset(dis,-1,sizeof(dis));
dis[beg]=0;
queue<int> q;
q.push(beg);
while(!q.empty())
{
int u=q.front();
q.pop();
h[u]=0;
for(int i=head[u];i!=-1;i=E[i].next)
{
int v=E[i].v;
if(E[i].flow>0&&update(u,v,E[i].w))
{
pre[v]=u;
path[v]=i;
if(!h[v])
{
h[v]=1;
q.push(v);
}
}
}
}
if(pre[end]==-1)
return false;
return true;
}
int maxcost_maxflow()
{
int ans=0;
while(spfa())
{
int Min=1;
for(int i=end;i!=beg;i=pre[i])
{
E[path[i]].flow-=Min;
E[path[i]^1].flow+=Min;
}
ans+=dis[end];
}
return ans;
}
}G;
int main(void)
{
int n;
while(scanf("%d",&n)!=EOF)
{
beg=0;
end=2*n*n+1;
G.init(end);
G.insert(beg,1,0,2);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
int u=(i-1)*n+j;
int v=u+n*n;
G.insert(u,v,x,1);
G.insert(u,v,0,1);
if(i<n)
G.insert(v,u+n,0,1);
if(j<n)
G.insert(v,u+1,0,1);
}
G.insert(2*n*n,end,0,2);
printf("%d/n",G.maxcost_maxflow());
}
}


这题是2686的加强版,用2686的方法照样可以解决,改成滚动数组就可以,另外也有网络流的解法:

拿第一个样例来说:

10 3

5 10

我们可以把每一个点看成两个映像,第一个看成 1与5,第二个 2与6,第三个 3与7,第四个 4与8,外加一个源点 0,汇点 9~

就变成了一个二分图:

1 5

2 6

0 3 7 9

4 8

接下来就是如何建图了:

1. 首先是源点,因为是从左上角开始,那么很好想,源点0与1连一条边,因为要两条路,那么源点过来的容量要为2,同理是汇点 9 与 8 连边,也是容量为2,两条边的费用都是0;

2. 其次是map[][]图如何对映到二分图上,就拿(1,1)这个点来说,首先它自己和自己的映像(1与5)之间是要建一条费用为map[1][1]即10的边,容量为1,代表(1,1)这个点走过了(走过了就得加上这条边的费用,将点与边对映上去);其次,(1,1)这个点它是可以走到(1,2)与(2,1)这两个点的:

模拟一下二分图,0走到1,1走到5,代表(1,1)这个点走过了,因为5到9是没有边的,

接下来为了能走到汇点9,

那么5应该回到二分图的左边,走到2或者3的位置,再由二分图的左边走向右边.....可以好好想下这个过程!所以得建5到2,和5到3的边(2,与3对映的是(1,2),(2,1)两点),这条边的容量为1,费用要为0,因为从(1,1)这个点走过来的,加上的只是(1,1)这个点的费用,这在1走到5的时候已经加过了!!要从2,3走到右边,走的时候自然会加上,所以费用为0,不然会导致重复加!

建边真的很奇妙,也就难在这里了,建好图之后就很简单,还是得多做题,接触多一点的建边模型!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: