hdu3605 Escape题解

来源:互联网 发布:如何防范网络陷阱 编辑:程序博客网 时间:2024/06/04 01:33

传送门

2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets. 
Input
More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet. 
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most.. 
0 <= ai <= 100000 
Output
Determine whether all people can live up to these stars 
If you can output YES, otherwise output NO. 
Sample Input
1 1112 21 01 01 1
Sample Output
YESNO
这道题要注意n的取值范围,10的5次方,显然不能直接套模板,肯定会TLE(但是自己还是犯了这种错误,还是太菜了)。然后我们会注意到,它的m的取值范围最大只有10,所以说对于每一个人来说,他适合某个星球的状况最多有2的10次方中。

显然有很多点是重复的,这时可以采取缩点的方法,将重复的当成一个点来处理。如何将重复的点看成一个点来处理呢?因为适合不适合是用0和1来表示的,所以我们很容易想到二进制。

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

今天wa了一上午真的是心痛,wa的原因还特别的搞笑。。。。真是说多了都是泪啊啊啊啊


#include<stdio.h>#include<iostream>#include<set>#include<queue>#include<algorithm>#include<math.h>#include<string.h>#include<string>#include<vector>using namespace std;const int inf = 0x3f3f3f3f;const int MX = 1025;const int MXE = 1000000;struct MaxFlow {//最大流模板,这个模板是照着日天的模板写的,码风很棒    struct Edge {        int v, w, nxt;    } edge[MXE];    int tot, num, s, t;    int head[MX];    void init() {        memset(head, -1, sizeof(head));        tot = 0;    }    void add(int u, int v, int w) {        edge[tot].v = v;        edge[tot].w = w;        edge[tot].nxt = head[u];        head[u] = tot++;        edge[tot].v = u;        edge[tot].w = 0;        edge[tot].nxt = head[v];        head[v] = tot++;    }    int  d[MX], vis[MX], gap[MX];    void bfs() {        memset(d, 0, sizeof(d));        memset(gap, 0, sizeof(gap));        memset(vis, 0, sizeof(vis));        queue<int>q;        q.push(t);        vis[t] = 1;        while (!q.empty()) {            int u = q.front();            q.pop();            for (int i = head[u]; ~i; i = edge[i].nxt) {                int v = edge[i].v;                if (!vis[v]) {                    d[v] = d[u] + 1;                    gap[d[v]]++;                    q.push(v);                    vis[v] = 1;                }            }        }    }    int last[MX];    int dfs(int u, int f) {        if (u == t) return f;        int sap = 0;        for (int i = last[u]; ~i; i = edge[i].nxt) {            int v = edge[i].v;            if (edge[i].w > 0 && d[u] == d[v] + 1) {                last[u] = i;                int tmp = dfs(v, min(f - sap, edge[i].w));                edge[i].w -= tmp;                edge[i ^ 1].w += tmp;                sap += tmp;                if (sap == f) return sap;            }        }        if (d[s] >= num) return sap;        if (!(--gap[d[u]])) d[s] = num;        ++gap[++d[u]];        last[u] = head[u];        return sap;    }    int solve(int st, int ed, int n) {        int flow = 0;        num = n;        s = st;        t = ed;        bfs();        memcpy(last, head, sizeof(head));        while (d[s] < num) flow += dfs(s, inf);        return flow;    }} F;//最大流模板结束int is_find[1100];//记录一个人适应哪些星球的情况int main(){    int n , m ;    while(~scanf("%d%d" , &n , &m)){        memset(is_find , 0  ,sizeof(is_find));        F.init();        int s = 0 ;//超级源点        for(int i = 1 ; i <= n ; i ++){            int x = 0;            for(int j = 1 ; j <= m ; j ++){                int fit ;                scanf("%d" , &fit);                x = 2*x + fit ;            }            is_find[x]++;        }        int cnt = 0 ;        for(int i = 1 ; i < 1100 ; i ++){            if(is_find[i])                cnt ++;        }        int  t = cnt + m + 1 ;//超级汇点        int top = 1 ;        for(int i = 1 ; i < 1100 ; i ++){            if(is_find[i]){                F.add(s , top , is_find[i]) ;                int x = i ;                int z = cnt + m ;                while(x){                    int y = x % 2 ;                    if(y)                        F.add(top , z , inf);                    z -- ;                    x /= 2;                }                top ++ ;            }        }        for(int i = 1 ; i <= m ; i ++){            int num ;            scanf("%d" , &num);            if(num)                F.add(cnt + i , t , num);        }        int re = F.solve(s , t , cnt+m+2);        if(re >= n){            printf("YES\n");        }        else            printf("NO\n");    }    return 0;}




原创粉丝点击