poj 1486 网络流+tarjan

题意:给一堆矩形和一些点,每个矩形必须对应一个点,求对应的点唯一的矩形个数。

如果点在矩形内部那么从点向矩形连流量1的边,从S向点连流量1的边,从矩形向T连流量1的边。跑网络流。

跑出来的东西是一种方案。将这种方案变成另一种方案只需要找到所有边剩余流量都为1的环,这样的环一定是偶环且正向边和反向边交替排列。那么把正向边流量流掉,把反向边流量退回就是一种新方案。

那么只需要跑一遍tarjan,如果矩形和在网络流中和他匹配的点不在一个强连通分量中,那么这个矩形的方案就是唯一的。

#include <queue>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 1100
#define inf 1e9
#define M 2100000
int n,Case;
int X1[N],X2[N],Y1[N],Y2[N];
struct awork_flow
{
    int head[N<<1],nex[M],to[M],val[M],tot;
    int deep[N<<1],S,T;
    queue<int>que;
    void init()
    {
        memset(head,0,sizeof(head));
        tot=1;
    }
    void add(int x,int y,int z)
    {
        tot++;
        nex[tot]=head[x];head[x]=tot;
        to[tot]=y;val[tot]=z;
    }
    int dfs(int x,int mv)
    {
        if(x==T)return mv;
        int tmp=0;
        for(int i=head[x];i;i=nex[i])
            if(val[i]&&deep[to[i]]==deep[x]+1)
            {
                int t=dfs(to[i],min(mv-tmp,val[i]));
                if(!t)deep[to[i]]=-1;
                tmp+=t;val[i]-=t;
                val[i^1]+=t;
                if(tmp==mv)break;
            }
        return tmp;
    }
    int bfs()
    {
        while(!que.empty())que.pop();
        que.push(S);
        memset(deep,-1,sizeof(deep));
        deep[S]=0;
        while(!que.empty())
        {
            int tmp=que.front();que.pop();
            for(int i=head[tmp];i;i=nex[i])
                if(val[i]&&deep[to[i]]==-1)
                {
                    deep[to[i]]=deep[tmp]+1;
                    if(to[i]==T)return 1;
                    que.push(to[i]);
                }
        }
        return 0;
    }
    int dinic()
    {
        int ret=0;
        while(bfs())
            ret+=dfs(S,inf);    
        return ret;
    }
}a;
struct Tarjan
{
    int dfn[N<<1],low[N<<1],bel[N<<1];
    int st[N<<1],top,cnt,ins[N<<1],tot;
    void init()
    {
        top=0;cnt=0;tot=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++cnt;st[++top]=x;
        ins[x]=1;
        for(int i=a.head[x];i;i=a.nex[i])
            if(a.val[i])
            {
                if(!dfn[a.to[i]])tarjan(a.to[i]),low[x]=min(low[x],low[a.to[i]]);
                else if(ins[a.to[i]])low[x]=min(low[x],dfn[a.to[i]]);
            }
        if(dfn[x]==low[x])
        {
            int t=st[top--];bel[t]=++tot;
            ins[t]=0;
            while(t!=x)
            {
                t=st[top--];
                bel[t]=tot;ins[t]=0;
            }
        }
    }
}b;
int main()
{
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d%d%d",&X1[i],&X2[i],&Y1[i],&Y2[i]);
        a.init();b.init();
        for(int i=1,x,y;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            for(int j=1;j<=n;j++)
                if(X1[j]<=x&&X2[j]>=x&&Y1[j]<=y&&Y2[j]>=y)
                    a.add(i+n,j,1),a.add(j,i+n,0);
        }
        a.S=n*2+1;a.T=n*2+2;
        for(int i=1;i<=n;i++)a.add(a.S,i+n,1),a.add(i+n,a.S,0);
        for(int i=1;i<=n;i++)a.add(i,a.T,1),a.add(a.T,i,0);
        a.dinic();
        for(int i=1;i<=a.T;i++)
            if(!b.dfn[i])b.tarjan(i);
        int cnt=0;
        printf("Heap %d\n",++Case);
        for(int i=1;i<=n;i++)
            for(int j=a.head[i];j;j=a.nex[j])
                if(a.val[j]&&a.to[j]>n&&a.to[j]<a.S&&b.bel[i]!=b.bel[a.to[j]])
                {
                    cnt++;
                    printf("(%c,%d) ",i+'A'-1,a.to[j]-n);
                }
        if(!cnt)puts("none");
        else puts("");
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值