首页 > 代码库 > BZOJ 2229 最小割

BZOJ 2229 最小割

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2229

题意:给定一个带权无向图。若干询问,每个询问回答有多少点对(s,t)满足s和t的最小割小于等于x。

思路:对于两个点(s,t)的最小割。这个最小割将将所有点分成左右两个集合X、Y。对于X中任意一点a与Y中任意一点b,(a,b)的最小割小于等于(s,t)的最小割。因此,每次递归计算分成的两个集合的最小割,更新答案。

 

struct node{    int v,cap,next;};node edges[N*N*10];int head[N],e;void add(int u,int v,int cap){    edges[e].v=v;    edges[e].cap=cap;    edges[e].next=head[u];    head[u]=e++;}void Add(int u,int v,int cap){    add(u,v,cap);    add(v,u,0);}int pre[N],cur[N],num[N],h[N];int Maxflow(int s,int t,int n){    int i;    for(i=0;i<=n;i++) cur[i]=head[i],num[i]=h[i]=0;    int u=s,Min,k,v;    int ans=0;    while(h[u]<n)    {        if(u==t)        {            Min=INF;            for(i=s;i!=t;i=edges[cur[i]].v)            {                k=cur[i];                if(edges[k].cap<Min) Min=edges[k].cap,v=i;            }            ans+=Min; u=v;            for(i=s;i!=t;i=edges[cur[i]].v)            {                k=cur[i];                edges[k].cap-=Min;                edges[k^1].cap+=Min;            }        }        for(i=cur[u];i!=-1;i=edges[i].next)        {            if(edges[i].cap>0&&h[u]==h[edges[i].v]+1) break;        }        if(i!=-1)        {            cur[u]=i;            pre[edges[i].v]=u;            u=edges[i].v;        }        else        {            if(--num[h[u]]==0) break;            k=n;            cur[u]=head[u];            for(i=head[u];i!=-1;i=edges[i].next)            {                if(edges[i].cap>0&&h[edges[i].v]<k)                {                    k=h[edges[i].v];                }            }            num[k+1]++;            h[u]=k+1;            if(u!=s) u=pre[u];        }    }    return ans;}int List[N][N],a[N][N],p[N][N];int n,m;int MinCut[N][N];int b[N];void build(int s,int t){    clr(head,-1); e=0;    int i,j,u,v;    FOR1(i,n)    {        u=i;        for(j=1;j<=List[u][0];j++)        {            v=List[u][j];            if(u!=t&&v!=s) Add(u,v,a[u][v]);        }    }}int visit[N];void DFS(int u){    visit[u]=1;    int i,v;    for(i=head[u];i!=-1;i=edges[i].next)    {        v=edges[i].v;        if(edges[i].cap>0&&!visit[v]) DFS(v);    }}void DFS(int L,int R){    if(L==R) return;    int s=b[L],t=b[R];    build(s,t);    int temp=Maxflow(s,t,n);    clr(visit,0); DFS(s);    int i,j,u,v,X[N],Y[N],xNum=0,yNum=0;    for(i=L;i<=R;i++)    {        if(visit[b[i]]) X[++xNum]=b[i];        else Y[++yNum]=b[i];    }    FOR1(i,n) if(visit[i]) FOR1(j,n) if(!visit[j])    {        u=i; v=j;        MinCut[u][v]=MinCut[v][u]=min(MinCut[u][v],temp);    }    FOR1(i,xNum) b[L+i-1]=X[i];    FOR1(j,yNum) b[L+xNum+j-1]=Y[j];    DFS(L,L+xNum-1);    DFS(L+xNum,R);}int main(){    rush()    {        RD(n,m);        int i,j,u,v,w;        FOR1(i,n) List[i][0]=0;        clr(a,0); clr(p,0);        FOR1(i,m)        {            RD(u,v,w);            if(!p[u][v])            {                List[u][++List[u][0]]=v;                List[v][++List[v][0]]=u;                p[u][v]=p[v][u]=1;            }            a[u][v]+=w;            a[v][u]+=w;        }        FOR1(i,n) b[i]=i;        FOR1(i,n) FOR1(j,n) MinCut[i][j]=INF;        DFS(1,n);        int Q,x,ans;        RD(Q);        while(Q--)        {            RD(x); ans=0;            FOR1(i,n) for(j=i+1;j<=n;j++) if(MinCut[i][j]<=x) ans++;            PR(ans);        }        puts("");    }}