BZOJ2893: 征服王

来源:互联网 发布:手机淘宝体验中心在哪 编辑:程序博客网 时间:2024/04/28 14:20

题目链接

【分析】

首先,第一步tarjan缩点还是很容易想到的。
一个点至少要经过一次,所以拆点,连两条边,第一条流量为1,费用为1,第二条流量为INF,费用为0。
连通块之间连边,流量为INF,费用为0。 若块x可作为起点,则由S–>x’连边,流量为INF,费用为0。若可作为终点,则由x”–>T连边,流量为INF,费用为0。 增广次数即为答案。

(又是一道把我心态做崩的题。。一开始打成了每条边走一次╮(╯▽╰)╭。。三个小时才发现错了。。蠢得可以。)

【代码】

#include <cstdio>#include <iostream>#include <queue>#include <vector>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#define N 2005#define M 100005#define INF 1000000000using namespace std;typedef long long ll;typedef pair<ll,ll> pa;int read(){    int x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,cnt=1,S,T,ans,CaseT,Cnt,num_s,num_t,ind,scc,Ans,sum;int b[M],p[N],nextedge[M],w[M],c[M];int B[20005],P[N],Next[20005];int Dis[N],Pre[N],Dfn[N],Low[N];int aa[N],bb[N];bool Flag[N],Instack[N],Mark[N];int Belong[N];void Add(int x,int y,int z,int cost){    cnt++;    b[cnt]=y;    nextedge[cnt]=p[x];    p[x]=cnt;    w[cnt]=z;    c[cnt]=cost;}void Anode(int x,int y,int z,int cost){    Add(x,y,z,cost);Add(y,x,0,-cost);}void Ins(int x,int y){    Cnt++;    B[Cnt]=y;    Next[Cnt]=P[x];    P[x]=Cnt;}void Input_Init(){    n=read();m=read();num_s=read(),num_t=read();    Cnt=ind=scc=ans=Ans=sum=0;    for(int i=1;i<=n;i++) P[i]=0;    for(int i=1;i<=num_s;i++) aa[i]=read();    for(int i=1;i<=num_t;i++) bb[i]=read();    for(int i=1;i<=m;i++)    {        static int x,y,z;        x=read(),y=read();        Ins(x,y);    }}stack<int>st;void Tarjan(int x){    Dfn[x]=Low[x]=++ind;    st.push(x);    Instack[x]=1;    for(int i=P[x];i;i=Next[i])    {        int v=B[i];        if(!Dfn[v])        {            Tarjan(v);            Low[x]=min(Low[x],Low[v]);        }        else if(Instack[v]) Low[x]=min(Low[x],Dfn[v]);    }    if(Low[x]==Dfn[x])    {        int now=-1;scc++;        while(now!=x)        {            now=st.top();st.pop();            Instack[now]=0;            Belong[now]=scc;        }    }}void Get_Scc(){    for(int i=1;i<=n;i++) Dfn[i]=0;    for(int i=1;i<=n;i++) if(!Dfn[i])        Tarjan(i); }void Build_Graph(){    T=scc<<1|1;    cnt=1;    for(int i=0;i<=T;i++) p[i]=Pre[i]=0;    for(int i=1;i<=n;i++) Mark[i]=0;    for(int i=1;i<=num_s;i++) Anode(0,Belong[aa[i]],INF,0);    for(int i=1;i<=num_t;i++) Anode(Belong[bb[i]]+scc,T,INF,0);    for(int i=1;i<=n;i++)    for(int j=P[i];j;j=Next[j])        if(Belong[i]!=Belong[B[j]])            Anode(Belong[i]+scc,Belong[B[j]],INF,0);    for(int i=1;i<=scc;i++)     {        Anode(i,i+scc,INF,0);        Anode(i,i+scc,1,-1);    }}bool Bfs(){    queue<int>q;    q.push(S);    for(int i=0;i<=T;i++) Dis[i]=INF;    Dis[S]=0;     while(!q.empty())    {        int k=q.front();q.pop();Flag[k]=0;        for(int i=p[k];i;i=nextedge[i])        {            int v=b[i],f=w[i];            if(Dis[v]>Dis[k]+c[i]&&f)            {                Dis[v]=Dis[k]+c[i];                Pre[v]=i;                if(!Flag[v])                {                    Flag[v]=1;                    q.push(v);                }            }        }    }    return Dis[T]!=INF;}bool Mcf(){    int Maxf=INF;    for(int i=Pre[T];i;i=Pre[b[i^1]])        Maxf=min(Maxf,w[i]);    for(int i=Pre[T];i;i=Pre[b[i^1]])    {        w[i]-=Maxf,w[i^1]+=Maxf;        ans-=c[i]*Maxf;    }}void MCF(){    while(Bfs())    {        int pre=ans;        Mcf();        if(pre==ans) break;        else Ans++;    }    if(ans!=scc) printf("no solution\n");    else printf("%d\n",Ans);}int main(){    CaseT=read();    while(CaseT--)    {        Input_Init();        Get_Scc();        Build_Graph();        MCF();    }    return 0;}
0 0
原创粉丝点击