• hdu3605 Escape (二分图多重匹配)


    很明显的一个二分图多重匹配,一开始用网络流直接建图,悲剧的TLE了

    之后,看了网上解释,缩点,确实大大简化了问题,也就可以AC了,600+ms

    一开始是这样建图的,先有虚拟源点s,汇点t,从s向每一个人连一条容量为1的边,每一个人向他适合的每一个planet连一条容量为1边,再从每一个planet连一条容量为w[i](该planet的容量)的边,很明显,判断最大流是否等于n即可。n为100000,而m只有10

    其实,在这道题目里面,人是无差别的,有区别是他们各自的选择,而总共只有10个planet,也就是所有的选择数也就(1<<10)种,所有选择都相同的人完全是等价的!!!

    可是,没想到还可以优化一下IO,突然刷到100+ms了,ORZ

    也可以匈牙利算法做,优化IO之后,171ms,也不慢,而且代码十分简单

    匈牙利算法
    #include<iostream>
    #include<string>
    using namespace std;
    const int N = 100002;
    int cap[12],map[N][12],vlink[12],link[12][N];
    bool vis[12];
    int n,m;
    int in()  
    {  
        char ch;  
        int a = 0;  
        while((ch = getchar()) == ' ' || ch == '\n');  
        a += ch - '0';  
        while((ch = getchar()) != ' ' && ch != '\n')  
        {  
            a *= 10;  
            a += ch - '0';  
        }  
        return a;  
    }
    int path(int s)
    {
        for(int i=0;i<m;i++)
        {
            if(map[s][i] && !vis[i])
            {
                vis[i]=true;
                if(vlink[i]<cap[i])
                {
                    link[i][vlink[i]++]=s;
                    return 1;
                }
                for(int j=0;j<vlink[i];j++)
                {
                    if(path(link[i][j]))
                    {
                        link[i][j]=s;
                        return 1;
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {
        while(scanf("%d %d",&n,&m)==2)
        {
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                    map[i][j]=in();
            for(int i=0;i<m;i++)
                scanf("%d",&cap[i]);
            memset(vlink,0,sizeof(vlink));
            bool flag=true;
            for(int i=0;i<n;i++)
            {
                memset(vis,false,sizeof(vis));
                if(!path(i))
                {
                    flag=false;
                    break;
                }
            }
            if(flag) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    最大流+缩点
    #include<iostream>
    #include<algorithm>
    #include<string>
    using namespace std;
    const int N = 120000+20;
    int n;
    int size,head[N],dis[N],gap[N],pre[N],cur[N];
    int mm[(1<<12)];
    struct edge
    {
        int v,w,next;
        edge(){}
        edge(int v,int next,int w=0):v(v),next(next),w(w){}
    }E[N*30];
    inline void insert(int u,int v,int w)
    {
        E[size]=edge(v,head[u],w);
        head[u]=size++;
        E[size]=edge(u,head[v],0);
        head[v]=size++;
    }
    int ISAP(int src,int des)
    {
        int maxflow=0;
        memset(dis,0,sizeof(dis));
        memset(gap,0,sizeof(gap));
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        int u =pre[src]=src;
        int aug=-1;
        while(dis[src]<n)
        {
    loop: for(int &i=cur[u];i!=-1;i=E[i].next)
          {
              int v=E[i].v;
              if(E[i].w && dis[u]==dis[v]+1)
              {
                  aug=min(aug,E[i].w);
                  pre[v]=u;
                  u=v;
                  if(v==des)
                  {
                      maxflow+=aug;
                      for(u=pre[u];v!=src;v=u,u=pre[u])
                      {
                          E[cur[u]].w-=aug;
                          E[cur[u]^1].w+=aug;
                      }
                      aug=INT_MAX;
                  }
                  goto loop;
              }
          }
          int mdis=n;
          for(int i=head[u];i!=-1;i=E[i].next)
          {
              int v=E[i].v;
              if(E[i].w && mdis>dis[v])
              {
                  cur[u]=i;
                  mdis=dis[v];
              }
          }
          if((--gap[dis[u]])==0)
              break;
          gap[dis[u]=mdis+1]++;
          u=pre[u];
        }
        return maxflow;
    }
    int in()  
    {  
        char ch;  
        int a = 0;  
        while((ch = getchar()) == ' ' || ch == '\n');  
        a += ch - '0';  
        while((ch = getchar()) != ' ' && ch != '\n')  
        {  
            a *= 10;  
            a += ch - '0';  
        }  
        return a;  
    }
    int main()
    {
        int m,a,b;
        while(scanf("%d %d",&n,&m)==2)
        {
            size=0;
            memset(head,-1,sizeof(head));
            memset(mm,0,sizeof(mm));
            for(int i=0;i<n;i++)
            {
                int t=0;
                for(int j=0;j<m;j++)
                {
                    a=in();
                    if(a) t|=(1<<j);
                }
                mm[t]++;
            }
            int nn=(1<<m),s=1,T=nn+m+2;
            int n1=n;
            n=T;
            for(int i=1;i<nn;i++)
            { 
                if(mm[i]==0) continue;
                insert(s,i+2,mm[i]);
                for(int j=0;j<m;j++)
                {
                    if(i&(1<<j))
                        insert(i+2,j+nn+2,mm[i]);
                }
            }
            for(int i=0;i<m;i++)
            {
                scanf("%d",&b);
                insert(i+nn+2,T,b);
            }
            if(ISAP(s,T)>=n1)
                puts("YES");
            else puts("NO");
        }
        return 0;
    }
  • 相关阅读:
    linux shell创建目录、遍历子目录
    linux shell写入单行、多行内容到文件
    如何起个好名字
    linux shell编程中的数组定义、遍历
    详解浏览器分段请求基础——Range,助你了解断点续传基础
    实现一个大文件上传和断点续传
    localStorage设置过期时间
    Python3 __slots__
    Nginx 流量统计分析
    argparse简要用法总结
  • 原文地址:https://www.cnblogs.com/nanke/p/2450185.html
Copyright © 2020-2023  润新知