bzoj1143 祭祀river 【网络流&&最长反链】

解题思路:

反链的定义就是一个点集满足其内部点两两不连通。
有定理如下:最长反链长度=最小可相交路径覆盖。
对偶定理:最长路径长度=最小反链覆盖。

先考虑有向无环图最小不相交路径覆盖

把原图中的每个点V拆成Vx和Vy,如果有一条有向边A->B,那么就加边Ax-By。这样就得到了一个二分图,最小路径覆盖=原图的节点数-新图最大匹配。

简单证明:一开始每个点都独立的为一条路径,总共有n条不相交路径。我们每次在二分图里加一条边就相当于把两条路径合成了一条路径,因为路径之间不能有公共点,所以加的边之间也不能有公共点,这就是匹配的定义。所以有:最小路径覆盖=原图的节点数-新图最大匹配。

有向无环图最小可相交路径覆盖
先floyd求出连通性后,把联通性作为边,最小不相交路径覆盖。
也可以每个Vy向Vx连INF的边,再正常连边求最小不相交路径覆盖(推荐)。

这道题既可以看作是求最长反链长度,也可以看作求连通性意义下的最大独立集。

关于更多二分图应用可见这里

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=205,M=10005,INF=0x3f3f3f3f;
int n,m,S,T;
int tot=1,first[N],cur[N],dis[N],to[M],cap[M],nxt[M];
queue<int>q;

void add(int x,int y,int z)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,cap[tot]=z;
    nxt[++tot]=first[y],first[y]=tot,to[tot]=x,cap[tot]=0;
}

bool BFS()
{
    for(int i=S;i<=T;i++)cur[i]=first[i],dis[i]=-1;
    while(!q.empty())q.pop();
    dis[S]=0,q.push(S);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int e=first[u];e;e=nxt[e])
        {
            int v=to[e];
            if(dis[v]==-1&&cap[e])
            {
                dis[v]=dis[u]+1;
                q.push(v);
                if(v==T)return true;
            }
        }
    }
    return false;
}

int dinic(int u,int flow)
{
    if(u==T)return flow;
    int res=0;
    for(int &e=cur[u];e;e=nxt[e])
    {
        int v=to[e];
        if(dis[v]==dis[u]+1&&cap[e])
        {
            int det=dinic(v,min(flow-res,cap[e]));
            cap[e]-=det,cap[e^1]+=det;
            res+=det;if(res==flow)break;
        }
    }
    if(res<flow)dis[u]=-1;
    return res;
}

int maxflow()
{
    int res=0;
    while(BFS())res+=dinic(S,INF);
    return res;
}

int main()
{
    //freopen("lx.in","r",stdin);
    n=getint(),m=getint();
    S=0,T=2*n+1;
    for(int i=1;i<=n;i++)add(S,i,1),add(i+n,T,1),add(i+n,i,INF);
    while(m--)
    {
        int x=getint(),y=getint();
        add(x,y+n,1); 
    }
    printf("%d\n",n-maxflow());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值