[20180325 hu测]舞动的夜晚(最大流+Tarjan缩点)

题目

传送门
Contest Hunter 是个好地方
这里写图片描述

题解

首先感谢@xp学长的讲解
这是道网络流好题;
原来理解错了题意,然后WA的非常惨。并不是跑一个sb最大流输出方案;
也就是使二分图最大匹配减少的边的数量;
算法如下:
我们先随便跑出一个最大流,在残余网络上进行tarjan找强连通分量缩点,因为在一个无向图中的强联通分量意味这可以相互通达,割掉其中一条边后并不会影响到汇点的路径;结合下图理解一下;
这里写图片描述
跑完最大流之后图是这个样子;
这里写图片描述
我们会发现其中1、2 、4、5构成了一个强联通分量
也就是说强联通分量里的边如果删掉之后一定可以通过其他的边到达,此时片可以把他们都看成一个点。
这里写图片描述
特别需要注意的是源点和汇点也需要跑Tarjan,因为如果有的点因为它的边已经满流而无法通过时,会和源点构成强联通分量。

代码

代码写的非常丑和冗长;

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const int maxn=500001;
const int inf=1e9;

int n,m,num,maxflow;
struct Edge{
    int next,to,dis,from,id;
}edge[maxn<<1];
int num_edge=-1,head[maxn],cur[maxn],deep[maxn];
int cnt,dfn[maxn],low[maxn],zhan[maxn],top,col[maxn],num_col;
bool ifin[maxn];
queue <int> q;

int read()
{
    char ch=getchar(); int now=0,f=1;
    while (ch<'0' || ch>'9') {ch=getchar(); if (ch=='-') f=-1;}
    while (ch>='0'&&ch<='9')
    {
        now=(now<<1)+(now<<3)+ch-'0';
        ch=getchar();
    }
    return now*f;
}

void add_edge(int from,int to,int dis,int id)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].dis=dis;
    edge[num_edge].from=from;
    edge[num_edge].id=id;
    edge[num_edge].to=to;
    head[from]=num_edge;
}
void add(int x,int y,
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值