HDU 3605Escape(缩点+网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3605

本来打算昨天写两道题的,结果这个题卡住了,最后才发现是最后的判断条件出错了,判断满流的条件应该是与n的比较,竟然写成与所有星球总容量的比较了。(最近大脑短路。。)

这题也不是完全自己想的,没想到缩点这一技巧,由于n的数据范围太大,普通的建图方法会超时超内存,需要缩点,因为对于每个点来说,一共只有2^10种方法,而最多一共有10W个点,显然有很多点是重复的,这时可以采取缩点的方法,将重复的当成一个点来处理。这样数据范围就缩小到了1024个点,速度大大提升。

建图思路是建一源点与汇点,将每种方法与源点相连,权值为这种方法重复的次数,将每个星球与汇点相连,权值为每个星球的最大容量,再将每种方法与星球相连,权值为INF,最后判断是否满流。

代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <algorithm>

using namespace std;
const int INF=1e9;
int head[2000], s, t, nv, n, cnt;
int num[2000], d[2000], pre[2000], cur[2000], q[2000], fei[2000];
struct node
{
    int u, v, next, cap;
}edge[1000000];
void add(int u, int v, int cap)
{
    edge[cnt].v=v;
    edge[cnt].cap=cap;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].v=u;
    edge[cnt].cap=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
void bfs()
{
    memset(num,0,sizeof(num));
    memset(d,-1,sizeof(d));
    int f1=0, f2=0, i;
    q[f1++]=t;
    d[t]=0;
    num[0]=1;
    while(f1>=f2)
    {
        int u=q[f2++];
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(d[v]==-1)
            {
                d[v]=d[u]+1;
                num[d[v]]++;
                q[f1++]=v;
            }
        }
    }
}
int isap()
{
    memcpy(cur,head,sizeof(cur));
    int flow=0, i, u=pre[s]=s;
    bfs();
    while(d[s]<nv)
    {
        if(u==t)
        {
            int f=INF, pos;
            for(i=s;i!=t;i=edge[cur[i]].v)
            {
                if(f>edge[cur[i]].cap)
                {
                    f=edge[cur[i]].cap;
                    pos=i;
                }
            }
            for(i=s;i!=t;i=edge[cur[i]].v)
            {
                edge[cur[i]].cap-=f;
                edge[cur[i]^1].cap+=f;
            }
            flow+=f;
            if(flow>=n)
                return flow;
            u=pos;
        }
        for(i=cur[u];i!=-1;i=edge[i].next)
        {
            if(d[edge[i].v]+1==d[u]&&edge[i].cap)
            {
                break;
            }
        }
        if(i!=-1)
        {
            cur[u]=i;
            pre[edge[i].v]=u;
            u=edge[i].v;
        }
        else
        {
            if(--num[d[u]]==0) break;
            int mind=nv;
            for(i=head[u];i!=-1;i=edge[i].next)
            {
                if(mind>d[edge[i].v]&&edge[i].cap)
                {
                    mind=d[edge[i].v];
                    cur[u]=i;
                }
            }
            d[u]=mind+1;
            num[d[u]]++;
            u=pre[u];
        }
    }
    return flow;
}
int main()
{
    int m, x, i, j, top, y, z, num, a[20];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(fei,0,sizeof(fei));
        cnt=0;
        s=0;
        top=0;
        num=0;
        for(i=1;i<=n;i++)
        {
            x=0;
            for(j=1;j<=m;j++)
            {
                scanf("%d",&y);
                x=x*2+y;
            }
            fei[x]++;
        }
        for(i=1;i<=1100;i++)
        {
            if(fei[i])
            {
                num++;
            }
        }
        t=num+m+1;
        nv=t+1;
        for(i=1;i<=1100;i++)
        {
            if(fei[i])
            {
                //printf("--%d %d\n", i, fei[i]);
                top++;
                add(s,top,fei[i]);
                x=i;
                z=m+1;
                while(x)
                {
                    y=x%2;
                    z--;
                    if(y)
                    {
                        add(top,z+num,INF);
                    }
                    //printf("--%d %d %d %d--",y, top, z, num);
                    x=x/2;
                }
                //printf("\n");
            }
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d",&x);
            add(i+num,t,x);
        }
        x=isap();
        if(x>=n)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

HDU 3605Escape(缩点+网络流之最大流),布布扣,bubuko.com

时间: 2024-10-23 23:41:34

HDU 3605Escape(缩点+网络流之最大流)的相关文章

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege

HDU 4183Pahom on Water(网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4183 这题题目意思很难看懂..我看了好长时间也没看懂..最终是从网上找的翻译..我就在这翻译一下吧. 意思大约是:有多个点,每个点给出坐标与半径,加入两个点相交,就可以从这两个点走.题目要求先从起点到终点,再从终点回到起点.从起点到终点的过程中,只能从频率小的走到频率大的点(前提是两点相交),从终点到起点的过程中,只能从频率大的走到频率小的.在走的过程中,除了起点与终点,别的只要走过就会消失,就是说

hdu 4289 Control(网络流 最大流+拆点)(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4289 Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1545    Accepted Submission(s): 677 Problem Description You, the head of Department o

HDU 4975 (杭电多校 #10 1005题)A simple Gaussian elimination problem.(网络流之最大流)

题目地址:HDU 4975 对这题简直无语...本来以为这题要用什么更先进的方法,结果还是老方法,这么卡时间真的好吗....比赛的时候用了判环的方法,一直TLE..后来换了矩阵DP的方式,加了加剪枝就过了..无语了.. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdio> #include <

HDU 4888 (杭电多校#3)Redraw Beautiful Drawings(网络流之最大流)

题目地址:HDU 4888 自己之所以弱真心是态度的问题,以后不能再偷懒了!!那次这个题一直没补,结果这次又遇到了..还有这次遇到的最小割权闭合问题,也一直没刷,所以这次遇到了也不会,连是最小割都不知道!!(突然想起来前面还有好多题拖到现在也没做...T U T)以后绝不能再拖拉了! 这题的建图是很容易的,主要是判断唯一性不好判断.这里是用的dfs找环来判断是否唯一,因为假如有环的话,说明环 中的数字是可以相互流动而且可以保证解依然正确.. 代码如下: #include <cstdio> #i

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

HDU 4292Food(网络流之最大流)

题目地址:HDU 4292 水题. 由于每个人只能有1份,所以需要拆点限制流量.建图方法为,建一源点与汇点,将食物与源点相连,权值为食物额数量,将饮料与汇点相连,权值为饮料数量..然后将人进行拆点为i和i',将对应的i与i'连边权值为1,将i与它所对应的YES的食物连边,将i'与它所对应的YES的饮料连边,一次求最大流. 代码如下: #include <iostream> #include <stdio.h> #include <string.h> #include &

HDU 3468 Treasure Hunting(BFS+网络流之最大流)

题目地址:HDU 3468 这道题的关键在于能想到用网络流.然后还要想到用bfs来标记最短路中的点. 首先标记方法是,对每一个集合点跑一次bfs,记录所有点到该点的最短距离.然后对于任意一对起始点来说,只要这个点到起点的最短距离+该点到终点的最短距离==起点到终点的最短距离,就说明这点在某条从起点到终点的最短路上. 然后以集合点建X集,宝物点建Y集构造二分图,将从某集合点出发的最短路中经过宝物点与该集合点连边.剩下的用二分匹配算法或最大流算法都可以.(为什么我的最大流比二分匹配跑的还要快....

HDU 3081Marriage Match II(二分+并查集+网络流之最大流)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3081 有一段时间没写最大流的题了,这题建图居然想了好长时间...刚开始是按着最终的最大流即是做多轮数去想建图,结果根本没思路,后来想了想,可以用二分答案的思想来找最终答案.然后很明显的并查集,但是并查集学的略渣,居然卡在并查集上了..= =. 但是也不是并查集的事..是我建图的思想太正了,稍微用点逆向思维并查集就可以很好利用了. 建图思路是:建立一个源点与汇点,将女孩与源点相连,男孩与汇点相连,权值