• 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;
    }
  • 相关阅读:
    AE 线编辑
    ArcEngine判断要素(feature)是否为multipart feature及分解(炸开)代码
    AE二次开发技巧之撤销、重做
    ArcEngine数据编辑--选择要素
    java语言体系的技术简介之JSP、Servlet、JDBC、JavaBean(Application)
    MVC开发模式详解
    数据库设计中常见表结构的设计技巧
    Eclipse 保存文件时自动格式化代码
    优化你的java代码性能
    Hibernate 与mybatis的区别
  • 原文地址:https://www.cnblogs.com/Gloid/p/9428149.html
Copyright © 2020-2023  润新知