题目大意:2012世界末日来了,科学家发现了一些星球可以转移人口,不过有的人可以在一些星球上生存有的人不行,而且每个星球都有一定的承载量,现在想知道是否所有的人都可以安全转移呢?

输入:首先输入一个N和M,表示人数和星球数,接着输入N行,每行有M个01组成的数,0表示第Ni个人无法再Mj号星球上生存,1表示可以生存,最后一行是每个星球的最大承载量。

分析:刚看的时候是一道比较裸的最大流题目,只要求出来最大流是否等于总人口数就行了,不过人的数量貌似是有点多的,刚开始没有管那么多直接上了最大流,不过也果然TLE,后来借鉴了一下别人的想法,就是缩点,我们发现M的值是特别小的,最大只有10,这就意味着有很多人的状态是相同的(2^10),所以可以把这些状态相同的人压缩到一起,这样最多也就1024个人了,大大缩减了复杂度,不过很不幸依然TLE!!!,好吧,认了,只能再去找一下sap的模板带入一下,刚开始随意找了一个模板套上,不过WA了,也不知道出了什么问题,,因为不了解SAP这东西,没办法,只能学一下SAP了,在网上找了一个很不错的演示 。其实和dinic还是挺相似的,只不过这个只做了一次的DFS是从汇点到源点进行的分层,然后寻找可行弧(也就是下面有没有可以与之相连的边),如果没有可行弧,就修改他的层号,然后就这样一直找下去,直到源点的层号大于总点数或者出现断层就可以停止了。ps.生命不息,学习不止啊。

sap演示 下载

下面是AC代码。

======================================================================================

#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<algorithm>
using namespace std; const int MAXN = ;
const int oo = 1e9+; struct Edge{int u, v, flow, next;}edge[MAXN*];
int Head[MAXN], cnt;
int used[MAXN], cur[MAXN], Stack[MAXN];
int Layer[MAXN], gap[MAXN], cntv;///节点的总个数 void InIt()
{
    cnt = ;
    memset(Head, -, sizeof(Head));
    memset(used, , sizeof(used));
}
void AddEdge(int u, int v, int flow)
{
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].flow = flow;
    edge[cnt].next = Head[u];
    Head[u] = cnt++;     edge[cnt].u = v;
    edge[cnt].v = u;
    edge[cnt].flow = ;
    edge[cnt].next = Head[v];
    Head[v] = cnt++;
} void BFS(int End)
{
    memset(Layer, -, sizeof(Layer));
    memset(gap, , sizeof(gap));
    queue<int> Q;
    Q.push(End);
    Layer[End] = , gap[] = ;     while(Q.size())
    {
        int u = Q.front();
        Q.pop();         for(int j=Head[u]; j!=-; j=edge[j].next)
        {
            int v = edge[j].v;             if(Layer[v] == -)
            {
                Layer[v] = Layer[u] + ;
                gap[Layer[v]]++;
                Q.push(v);
            }
        }
    }
} int SAP(int start, int End)
{
    int j, top=, u = start, MaxFlow=;     BFS(End);
    cntv = End;
    memcpy(cur, Head, sizeof(Head));     while(Layer[start] < cntv)
    {///源点的层次小于总结点数,汇点是0层         if(u == End)
        {
            int MinFlow = oo, location;///记录下最小流量边的位置,出栈时候用             for(j=; j<top; j++)
            {
                int i = Stack[j];
                if(MinFlow > edge[i].flow)
                {
                    MinFlow = edge[i].flow;
                    location = j;
                }
            }
            for(j=; j<top; j++)
            {///所有的边减去路径上的最小流量
                int i = Stack[j];                 edge[i].flow -= MinFlow;
                edge[i^].flow += MinFlow;
            }             MaxFlow += MinFlow;
            top = location;///退栈
            u = edge[Stack[top]].u;
        }
        else if(gap[Layer[u]-] == )
            break;///u所在的层下面的层没有了,出现了断层,也就没有了可行弧         for(j=cur[u]; j!=-; j=edge[j].next)
        {///如果u有可行弧就停止
            if(Layer[u]==Layer[edge[j].v]+ && edge[j].flow)
                break;
        }         if(j != -)
        {///找到了可行弧
            cur[u] = j;///u点的可行弧是j
            Stack[top++] = j;///记录下这条边
            u = edge[j].v;
        }
        else
        {///没有找到可行弧,修改标号
            int MinIndex = cntv;             for(j=Head[u]; j!=-; j=edge[j].next)
            {///查找与u相连的最小的层是多少
                if(edge[j].flow && MinIndex > Layer[edge[j].v])
                {///记录下这条可行弧,下次可以直接访问这条边
                    MinIndex = Layer[edge[j].v];
                    cur[u] = j;
                }
            }             gap[Layer[u]] -= ;///u改变层,所以u原来所在层的点数减去1
            Layer[u] = MinIndex + ;
            gap[Layer[u]] += ;             if(u != start)
            {///返回上一层
                u = edge[Stack[--top]].u;
            }
        }
    }     return MaxFlow;
} int main()
{
    int N, M;     while(scanf("%d%d", &N, &M) != EOF)
    {
        int i, j, u, Ni=pow(, M), start=Ni+M+, End=start+;
        char ch;         InIt();         for(i=; i<=N; i++)
        {
            u = ;
            for(j=; j<=M; j++)
            {
                while(ch = getchar(), ch ==' ' || ch == '\n');
                u = u* + ch-'';
            }
            used[u]++;///这种状态的人+1
        }         for(i=; i<Ni; i++)
        {
            if(used[i])
            {
                AddEdge(start, i, used[i]);
            }
        }         for(i=; i<=M; i++)
        {
            scanf("%d", &u);
            AddEdge(i+Ni, End, u);
        }         for(i=; i<Ni; i++) if(used[i])
        {///如果这种状态有人
            u = i;
            for(j=M; j>; j--)
            {
                if(u&)
                {///最后一位是1
                    AddEdge(i, Ni+j, used[i]);
                }
                u = u >> ;
            }
        }         int MaxFlow = SAP(start, End);         if(MaxFlow == N)
            printf("YES\n");
        else
            printf("NO\n");
    }     return ;
}

M - Escape - HDU 3605 - (缩点+最大流SAP)的更多相关文章

  1. Escape HDU - 3605(归类建边)

    Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  2. hdu 3605 /状态合并最大流

    题意:N个人去m个星球,给出n个人可以去哪些星球的01矩阵.求是否能满足所有人都去.(n到10万,m<=10) 一看,起先一瞬间就建图,准备秒了,人向星球连边,直接最大流判断是否为n,提交超时. ...

  3. 网络流 E - Escape HDU - 3605

    2012 If this is the end of the world how to do? I do not know how. But now scientists have found tha ...

  4. Hdu 3605 Escape (最大流 + 缩点)

    题目链接: Hdu 3605  Escape 题目描述: 有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功? 解题思路: 正常情况下建图,不会爆内存,但是T ...

  5. HDU 3605 Escape(状压+最大流)

    Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Sub ...

  6. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

  7. HDU - 3605 Escape (缩点+最大流/二分图多重匹配)

    题意:有N(1<=N<=1e5)个人要移民到M(1<=M<=10)个星球上,每个人有自己想去的星球,每个星球有最大承载人数.问这N个人能否移民成功. 分析:可以用最大流的思路求 ...

  8. HDU 3605 Escape 最大流+状压

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3605 Escape Time Limit: 2000/1000 MS (Java/Others)    ...

  9. HDU 3605:Escape(最大流+状态压缩)

    http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...

随机推荐

  1. 动态代理 Proxy InvocationHandler

      前奏 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常 ...

  2. PHP 实现ajax的接收

    Ajax界面: 首先,理解本质,就是普通的一个提交在无刷新的情况下发出请求后得到响应,然后去针对你需要 的情况来做行为. <!DOCTYPE html> <html> < ...

  3. Access数据库数据转换Table.Json

    使用WPF组件 xaml <Window x:Class="JsonConvert.MainWindow" xmlns="http://schemas.micros ...

  4. Android项目代码混淆

    http://coolshell.info/blog/2015/03/Android-studio-prefrence.html 什么是Gradle Gradle是一种依赖管理工具,基于Groovy语 ...

  5. TSQL Challenge 1

    在老外网站发布的一些SQL问题,拿过来自己搞一下,后面我也会陆续转载一些问题,欢迎看到的朋友贴出自己的答案,交流一哈.对于技术问答题的描述,翻译远不不原版来的更好一些,下面我就贴出原版的题目,欢迎参与 ...

  6. 重新开始学习javase_控制程序流程

    @学习thinking in java 二.控制程序流程 负数使用 Java 运算符:运算符以一个或多个自变量为基础,可生成一个新值.自变量采用与原始方法调用不同的一种形式,但效果是相同的.根据以前写 ...

  7. Hibernate 事件监听

    事件监听是JDK中常见的一种模式. Hibernate中的事件监听机制可以对Session对象的动作进行监听,一旦发生了特殊的事件,Hibernate就会调用监听器类中的事件处理方法.在某些功能的设计 ...

  8. Git 远程仓库的管理和使用

    要参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库.远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写.同他人协作开发某 个项目时,需要管理这些远程仓库 ...

  9. SQL2008数据库连接服务器为主机名时连接成功,服务器为Ip地址时链接失败

    如图:

  10. Web Service相关工具的配置

    近期在学习Web Service Testing,使用到了soapUI这个工具,但是在学习之前,需要搭建Web Service环境,其中有关数据库的连接问题花费了我好多时间,主要还是自己对于很多配置不 ...