题目链接:https://cn.vjudge.net/problem/HDU-3605

题意:给你n个人,m个星球,每个人对这m个星球的都有一定的适应能力,每个星球都有一定的容纳量,问能否让所有的人在星球上生存。

刚开始做的时候一直TLE 不知道为什么,改着改着发现建图的时候,添了很多边,这样跑最大流非常慢,看了网上的思路才知道要缩点,因为星球最多才有10个,所以把每个星球适合住的人数存一下,当做源点与星球的边的流量,星球的最大容纳量当做星球与汇点的边的流量。

跑一遍dinic,最大流大于等于n即YES

否则NO

#include <algorithm>
#include <vector>
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;

const int MAX = (1ll << 31) - 1;

struct Edge{
    int to;
    int dis;
    int next;
} edges[1100];

int cur[2001], head[2000], edge_num = -1;
int n, m, s, t;

void addEdge2(int from, int to, int dis){
    edges[++edge_num].to = to;
    edges[edge_num].dis = dis;
    edges[edge_num].next = head[from];
    head[from] = edge_num;
}

void addEdge(int from, int to, int dis){
    addEdge2(from, to, dis);
    addEdge2(to, from, 0);
}

int d[2001],e[100],p[100];

int DFS(int u, int flow){
    if (u == t) return flow;
    int _flow = 0, __flow;
    for (int& c_e = cur[u]; c_e != -1; c_e = edges[c_e].next){
        int v = edges[c_e].to;
        if (d[v] == d[u] + 1 && edges[c_e].dis > 0){
            __flow = DFS(v, min(flow, edges[c_e].dis));
            flow -= __flow;
            edges[c_e].dis -= __flow;
            _flow += __flow;
            edges[c_e^1].dis += __flow;
            if (!flow)
                break;
        }
    }
    if (!_flow) d[u] = -1;
    return _flow;
}

bool BFS(){
    for(int i=s;i<=t;i++) d[i] = -1;
    queue<int> que; que.push(s);
    d[s] = 0; int u, _new;

    while (!que.empty()){
        u = que.front(), que.pop();
        for (int i = head[u]; i != -1; i = edges[i].next){
            _new = edges[i].to;

            if (d[_new] == -1 && edges[i].dis > 0){
                d[_new] = d[u] + 1;
                que.push(_new);
            }
        }
    }
    return (d[t] != -1);
}

void dinic(){
    int max_flow = 0;

    while (BFS()){
        for (int i = s; i <= t; ++i) cur[i] = head[i];
        max_flow += DFS(s, MAX);
    }

    printf("%s\n", max_flow>=n?"YES":"NO");
}


int main(){
    while(scanf("%d%d",&n,&m)!=EOF) {
        int flag=0;
        memset(e,0,sizeof(e));
        for(int i=0;i<=100;i++) head[i] = -1;
        for(int i=1;i<=n;i++) {
            int sum=0,x;
            for(int j=0;j<m;j++) {
                scanf("%d",&x);
                if(x)  e[j]++,sum++;
            }
            if(!sum)flag=1;
        }
        for(int i=0;i<m;i++) {
            scanf("%d",&p[i]);
        }
        if(flag) {
            printf("NO\n");
            continue;
        }
        for(int i=0;i<m;i++) {
            if(e[i]) {
                addEdge(0,i+1,e[i]);
            }
            if(p[i]) {
                addEdge(i+1,m+1,p[i]);
            }
        }

        s = 0, t = m + 1;
        dinic();
    }

	return 0;
}

 

 

当然还有更简单的,直接求上图的最小割即为最大流,由于最小割就是每条增广路的饱和边之和

即ans += min(e[i], e[i + m]);

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

int n,m,x,nump[1050],p[15],e[30]; 

int solve()
{
   int ans=0;
   for (int i=0;i<m;i++) ans+=min(e[i],e[i+m]);
   return ans;
}

int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        memset(p,0,sizeof(p));
        memset(e,0,sizeof(e));
        int flag=0;
        for (int i=1;i<=n;i++)
        {
            int sum=0;
            for (int j=1;j<=m;j++)
            {
                scanf("%d",&x);
                if (x) e[j-1]++,sum++;
            }
            if(!sum)flag=1;
        }
        for (int i=0;i<m;i++) scanf("%d",&p[i]);
        if (flag)
        {
            printf("NO\n");
            continue;
        }
        for (int i=0;i<m;i++) if (p[i]) e[i+m]+=p[i];
        int ans=solve();
        if (ans>=n) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}