HDOJ 3491

今天学习了一个边比较少的图的表示方法,边链表示法


一看就知道是网络流,但是怎么构建呢?


把每点a拆成两个a 跟 a‘,两点间的边权为该店的值


那么最后的答案应该为source’到sink的最大流


我的代码


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 40001


int n, m;


int source, sink;


int next[201];                      //next【i】表示点i的第一个边node的下标



int que[MAX], inque[MAX], num;
int h[MAX];


struct Node
{
int to;
int flow;
int next;
}node[MAX]; //node存放边信息,next成员是下一个边的信息,构成边链


int cnt;


int min(int a, int b)
{
return a < b ? a : b;
}


int add(int from, int to, int flow)
{
cnt ++;


node[cnt].to = to;
node[cnt].flow = flow;
node[cnt].next = next[from];
next[from] = cnt;


cnt ++;
node[cnt].to = from;
node[cnt].flow = 0;
node[cnt].next = next[to];
next[to] = cnt;
return 0;
}


int bfs()
{
memset(inque, 0, sizeof(inque));
que[0] = source;
num = 0;
inque[source] = 1;
h[0] = 0;


int i;
int front = 0;
while(front <= num)
{
for(i = next[que[front]]; i != 0; i = node[i].next)
{
if(node[i].flow > 0 && !inque[node[i].to])
{
que[++ num] = node[i].to;
inque[node[i].to] = 1;
h[node[i].to] = h[que[front]] + 1;
if(node[i].to == sink)
return 1;
}
}
front ++;
}
return 0;
}


int dfs(int pre, int maxf)
{
int a;
if(pre == sink)
return maxf;
for(int i = next[pre]; i != 0; i = node[i].next)
{
if(node[i].flow > 0 && h[node[i].to] == h[pre] + 1)
{
a = dfs(node[i].to, min(maxf, node[i].flow));
if(!a)
continue;
node[i].flow -= a;
node[i ^ 1].flow += a;
return a;
}
}
h[pre] = -1;
return 0;
}




int maxFlow()
{
int get;
int result = 0;
while(bfs())
{
while(get = dfs(source, MAX))
{
result += get;
}
}
return result;
}


int main()
{
int a, b;
int i;
int cases;
scanf("%d", &cases);
while(cases --)
{
cnt = 1;
memset(next, 0, sizeof(next));
scanf("%d%d%d%d", &n, &m, &source, &sink);
for(i = 1; i <= n; i ++)
{
scanf("%d", &a);
add(i, n + i, a); //注意双向边构图的方法,拆的点一个是接受点,一个是流出点
}
for(i = 1; i <= m ; i ++)
{
scanf("%d%d", &a, &b);
add(n + a, b, MAX); //所以这两个都要才行,否则遗失了原本双向图的信息
add(b + n, a, MAX); //所以这两个都要才行,否则遗失了原本双向图的信息
}
source += n;
printf("%d\n", maxFlow());
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值