设为首页 收藏本站
查看: 1258|回复: 0

[经验分享] M

[复制链接]

尚未签到

发表于 2015-9-20 14:46:43 | 显示全部楼层 |阅读模式
  题目大意: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 = 1110;
const int oo = 1e9+7;
struct Edge{int u, v, flow, next;}edge[MAXN*100];
int Head[MAXN], cnt;
int used[MAXN], cur[MAXN], Stack[MAXN];
int Layer[MAXN], gap[MAXN], cntv;///节点的总个数

void InIt()
{
    cnt = 0;
    memset(Head, -1, sizeof(Head));
    memset(used, 0, 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;
    Head = cnt++;
    edge[cnt].u = v;
    edge[cnt].v = u;
    edge[cnt].flow = 0;
    edge[cnt].next = Head[v];
    Head[v] = cnt++;
}
void BFS(int End)
{
    memset(Layer, -1, sizeof(Layer));
    memset(gap, 0, sizeof(gap));
    queue<int> Q;
    Q.push(End);
    Layer[End] = 0, gap[0] = 1;
    while(Q.size())
    {
        int u = Q.front();
        Q.pop();
        for(int j=Head; j!=-1; j=edge[j].next)
        {
            int v = edge[j].v;
            if(Layer[v] == -1)
            {
                Layer[v] = Layer + 1;
                gap[Layer[v]]++;
                Q.push(v);
            }
        }
    }
}
int SAP(int start, int End)
{
    int j, top=0, u = start, MaxFlow=0;
    BFS(End);
    cntv = End;
    memcpy(cur, Head, sizeof(Head));
    while(Layer[start] < cntv)
    {///源点的层次小于总结点数,汇点是0层

        if(u == End)
        {
            int MinFlow = oo, location;///记录下最小流量边的位置,出栈时候用

            for(j=0; j<top; j++)
            {
                int i = Stack[j];
                if(MinFlow > edge.flow)
                {
                    MinFlow = edge.flow;
                    location = j;
                }
            }
            for(j=0; j<top; j++)
            {///所有的边减去路径上的最小流量
                int i = Stack[j];
                edge.flow -= MinFlow;
                edge[i^1].flow += MinFlow;
            }
            MaxFlow += MinFlow;
            top = location;///退栈
            u = edge[Stack[top]].u;
        }
        else if(gap[Layer-1] == 0)
            break;///u所在的层下面的层没有了,出现了断层,也就没有了可行弧

        for(j=cur; j!=-1; j=edge[j].next)
        {///如果u有可行弧就停止
            if(Layer==Layer[edge[j].v]+1 && edge[j].flow)
                break;
        }
        if(j != -1)
        {///找到了可行弧
            cur = j;///u点的可行弧是j
            Stack[top++] = j;///记录下这条边
            u = edge[j].v;
        }
        else
        {///没有找到可行弧,修改标号
            int MinIndex = cntv;
            for(j=Head; j!=-1; j=edge[j].next)
            {///查找与u相连的最小的层是多少
                if(edge[j].flow && MinIndex > Layer[edge[j].v])
                {///记录下这条可行弧,下次可以直接访问这条边
                    MinIndex = Layer[edge[j].v];
                    cur = j;
                }
            }
            gap[Layer] -= 1;///u改变层,所以u原来所在层的点数减去1
            Layer = MinIndex + 1;
            gap[Layer] += 1;
            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(2, M), start=Ni+M+1, End=start+1;
        char ch;
        InIt();
        for(i=1; i<=N; i++)
        {
            u = 0;
            for(j=1; j<=M; j++)
            {
                while(ch = getchar(), ch ==' ' || ch == '\n');
                u = u*2 + ch-'0';
            }
            used++;///这种状态的人+1
        }
        for(i=1; i<Ni; i++)
        {
            if(used)
            {
                AddEdge(start, i, used);
            }
        }
        for(i=1; i<=M; i++)
        {
            scanf("%d", &u);
            AddEdge(i+Ni, End, u);
        }
        for(i=1; i<Ni; i++) if(used)
        {///如果这种状态有人
            u = i;
            for(j=M; j>0; j--)
            {
                if(u&1)
                {///最后一位是1
                    AddEdge(i, Ni+j, used);
                }
                u = u >> 1;
            }
        }
        int MaxFlow = SAP(start, End);
        if(MaxFlow == N)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-116347-1-1.html 上篇帖子: SAP RFC user 最小权限 下篇帖子: Entries missing in table T028G T-CODE: OT51 SAP 传输配置操作为用户操作 SAP网银接口
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表