zoukankan      html  css  js  c++  java
  • BZOJ5251 八省联考2018劈配(网络流)

      劈配,匹配,网络流。那么考虑怎么跑网络流。

      先看第一问。首先套路的建出超源超汇。不用想也知道导师向汇连容量为战队人数上限的边。特别地,给出局也建一个点,向汇连容量inf的边(似乎没有必要)。对于一个新学员,假设我们已经知道了之前的学员的最优选择,可以把之前的每名学员和可以选择的导师连边,并由源向学员连容量为1的边。然后对于该名新学员,先只连最优选择的边,如果此时跑出的最大流不等于学员数,则表明这名学员无法选择最优,那么删掉最优边(此时这些边里一定没有流量,可以通过容量改为0实现)并连上次优边,次优边还是不行的话继续,一直这样下去直到最大流等于学员数。第一问就做完了。至于复杂度,O(能过)。

      然后是第二问。对于每个人可以二分答案,然后跑最大流看其是否满足。似乎需要访问网络的历史状态?可持久化网络流!这玩意似乎没法可持久化啊……那就暴力记下来呗。由于有C的限制,这里面的边不会很多。于是就做完了,O(能过)。还有一种做法是先连上该学员可以选择的边,然后从第一名开始依次把最优选择加进去跑,直到无法满足,可能会快不少。

     

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 210
    #define S 0
    #define T 404
    int test,c,n,m,b[N],s[N],p[N<<1],cnt[N],t;
    int cur[N<<1],d[N<<1],q[N<<1],ans,cho[N];
    vector<int> a[N][N];
    struct data{int to,nxt,cap,flow;
    }edge[N*N<<2],hisedge[N][2510];
    void addedge(int x,int y,int z)
    {
        t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,p[x]=t;
        t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,p[y]=t;
    }
    void addedge(int x,int y,int cap,int flow)
    {
        t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=cap,edge[t].flow=flow,p[x]=t;
        t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=-flow,p[y]=t;
    }
    void init()
    {
        for (int i=1;i<=m;i++) b[i]=read();
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m+1;j++)
            a[i][j].clear();
            for (int j=1;j<=m;j++)
            {
                int x=read();
                if (x) a[i][x].push_back(j);
            }
            a[i][m+1].push_back(m+1);
        }
        for (int i=1;i<=n;i++) s[i]=read();
    }
    bool bfs()
    {
        memset(d,255,sizeof(d));d[S]=0;
        int head=0,tail=1;q[1]=S;
        do
        {
            int x=q[++head];
            for (int i=p[x];~i;i=edge[i].nxt)
            if (d[edge[i].to]==-1&&edge[i].flow<edge[i].cap)
            {
                d[edge[i].to]=d[x]+1;
                q[++tail]=edge[i].to;
            }
        }while (head<tail);
        return ~d[T];
    }
    int work(int k,int f)
    {
        if (k==T) return f;
        int used=0;
        for (int i=cur[k];~i;i=edge[i].nxt)
        if (d[k]+1==d[edge[i].to])
        {
            int w=work(edge[i].to,min(f-used,edge[i].cap-edge[i].flow));
            edge[i].flow+=w,edge[i^1].flow-=w;
            if (edge[i].flow<edge[i].cap) cur[k]=i;
            used+=w;if (used==f) return f;
        }
        if (used==0) d[k]=-1;
        return used;
    }
    void dinic()
    {
        while (bfs())
        {
            memcpy(cur,p,sizeof(p));
            ans+=work(S,N);
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5251.in","r",stdin);
        freopen("bzoj5251.out","w",stdout);
        const char LL[]="%I64d";
    #else
        const char LL[]="%lld";
    #endif
        test=read(),c=read();
        while (test--)
        {
            n=read(),m=read();
            t=-1;
            memset(p,255,sizeof(p));
            memset(cnt,0,sizeof(cnt));
            init();
            for (int i=1;i<=m;i++) addedge(n+i,T,b[i]);
            addedge(n+m+1,T,N);
            for (int j=0;j<=t;j+=2)
            if (edge[j].cap) hisedge[0][++cnt[0]]=edge[j],hisedge[0][cnt[0]].nxt=edge[j^1].to;
            ans=0;
            for (int i=1;i<=n;i++)
            {
                addedge(S,i,1);
                for (int j=1;j<=m+1;j++)
                {
                    int tmp=t;
                    for (int k=0;k<a[i][j].size();k++)
                    addedge(i,n+a[i][j][k],1);
                    dinic();
                    if (ans==i) {cho[i]=j;break;}
                    for (int k=tmp+1;k<=t;k+=2) edge[k].cap=0;
                }
                for (int j=0;j<=t;j+=2)
                if (edge[j].cap) hisedge[i][++cnt[i]]=edge[j],hisedge[i][cnt[i]].nxt=edge[j^1].to;
            }
            /*for (int i=0;i<=n;i++)
            {
                for (int j=1;j<=cnt[i];j++)
                cout<<hisedge[i][j].nxt<<' '<<hisedge[i][j].to<<' '<<hisedge[i][j].cap<<' '<<hisedge[i][j].flow<<endl;
                cout<<endl;
            }*/
            for (int i=1;i<=n;i++) printf("%d ",cho[i]);
            cout<<endl;
            for (int i=1;i<=n;i++)
            {
                int l=0,r=i-1,add=-1;
                while (l<=r)
                {
                    int mid=l+r>>1;
                    memset(p,255,sizeof(p));
                    t=-1;
                    addedge(S,i,1);
                    for (int j=1;j<=s[i];j++)
                        for (int k=0;k<a[i][j].size();k++)
                        addedge(i,n+a[i][j][k],1);
                    for (int j=1;j<=cnt[mid];j++)
                    addedge(hisedge[mid][j].nxt,hisedge[mid][j].to,hisedge[mid][j].cap,hisedge[mid][j].flow);
                    ans=0;
                    dinic();
                    if (!ans) r=mid-1;
                    else l=mid+1,add=mid;
                }
                printf("%d ",i-add-1);
            }
            cout<<endl;
        }
        return 0;
    }
  • 相关阅读:
    Security headers quick reference Learn more about headers that can keep your site safe and quickly look up the most important details.
    Missing dollar riddle
    Where Did the Other Dollar Go, Jeff?
    proteus 与 keil 联调
    cisco router nat
    router dhcp and dns listen
    配置802.1x在交换机的端口验证设置
    ASAv931安装&初始化及ASDM管理
    S5700与Cisco ACS做802.1x认证
    playwright
  • 原文地址:https://www.cnblogs.com/Gloid/p/9428149.html
Copyright © 2011-2022 走看看