<每日一題>Day 9:POJ-3281.Dining(拆點 + 多源多匯+ 網絡流 )

Dining

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 24945   Accepted: 10985

Description數組

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.ide

Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not be able to stuff everybody, he wants to give a complete meal of both food and drink to as many cows as possible.this

Farmer John has cooked F (1 ≤ F ≤ 100) types of foods and prepared D (1 ≤ D ≤ 100) types of drinks. Each of his N (1 ≤ N ≤ 100) cows has decided whether she is willing to eat a particular food or drink a particular drink. Farmer John must assign a food type and a drink type to each cow to maximize the number of cows who get both.spa

Each dish or drink can only be consumed by one cow (i.e., once food type 2 is assigned to a cow, no other cow can be assigned food type 2).code

Inputorm

Line 1: Three space-separated integers:  NF, and  D 
Lines 2.. N+1: Each line  i starts with a two integers  Fi and  Di, the number of dishes that cow  i likes and the number of drinks that cow  i likes. The next  Fi integers denote the dishes that cow  i will eat, and the  Di integers following that denote the drinks that cow  i will drink.

Outputblog

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes

Sample Inputthree

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

Sample Outputip

3

Hintci

One way to satisfy three cows is: 
Cow 1: no meal 
Cow 2: Food #2, Drink #2 
Cow 3: Food #1, Drink #1 
Cow 4: Food #3, Drink #3 
The pigeon-hole principle tells us we can do no better since there are only three kinds of food or drink. Other test data sets are more challenging, of course.

Source

  都在代碼裏了,幹/drink.jpg

/*
    POJ 3281 最大流 + 拆點
    源點 -> food -> 牛左 -> 牛右 -> Drink -> 匯點
    建圖時注意將上面的全部邊的容量設置爲1,這樣就能夠保證一頭牛
    只吃一種食物喝一種飲料,轉化以後確定就知道是最大流了

    拆點技巧:爲了保證同一個東西知足兩個條件,則將其拆分爲兩個
    公共邊的點分別進行求解。

    嚶嚶嚶,爲何作完以後感受這個題其實建圖也是很好想的,就是拆個點,原諒本身太差
    唉,都是幻覺
*/

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn=1000+5, INF = 0x3f3f3f3f;
struct Edge
{
    Edge(){}
    Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
    int from,to,cap,flow;
};

struct Dinic
{
    int n,m,s,t;            //結點數,邊數(包括反向弧),源點與匯點編號
    vector<Edge> edges;     //邊表 edges[e]和edges[e^1]互爲反向弧
    vector<int> G[maxn];    //鄰接表,G[i][j]表示結點i的第j條邊在e數組中的序號
    bool vis[maxn];         //BFS使用,標記一個節點是否被遍歷過
    int d[maxn];            //從起點到i點的距離
    int cur[maxn];          //當前弧下標

    void init(int n,int s,int t)
    {
        this->n=n,this->s=s,this->t=t;
        for(int i=1;i<=n;i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap)
    {
        edges.push_back( Edge(from,to,cap,0) );
        edges.push_back( Edge(to,from,0,0) );
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS()
    {
        memset(vis,false,sizeof(vis));
        queue<int> Q;//用來保存節點編號的
        Q.push(s);
        d[s]=0;
        vis[s]=true;
        while(!Q.empty())
        {
            int x=Q.front(); Q.pop();
            for(int i=0; i<G[x].size(); i++)
            {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to] && e.cap>e.flow)
                {
                    vis[e.to]=true;
                    d[e.to] = d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a)
    {
        if(x==t || a==0)return a;
        int flow=0,f;//flow用來記錄從x到t的最小殘量
        for(int& i=cur[x]; i<G[x].size(); i++)
        {
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )>0 )
            {
                e.flow +=f;
                edges[G[x][i]^1].flow -=f;
                flow += f;
                a -= f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int Maxflow()
    {
        int flow=0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            flow += DFS(s,INF);
        }
        return flow;
    }
}Dinic;

int main() {
    int n, f, a, b, c, d;
    scanf("%d %d %d", &n, &f, &d);
    int s = n * 2 + f + d + 1, t = s + 1;
    Dinic.init(n, s, t);
    for(int i = 1; i <= f; i ++) {//n * 2 - 1 ~ n * 2 + f - 1存儲從s -> 食物的邊
        Dinic.AddEdge(s, n * 2 + i, 1);
    }
    for(int i = 1; i <= d; i ++) {//n * 2 + f ~ n * 2 + f + d - 1存儲從飲料 -> t的邊
        Dinic.AddEdge(n * 2 + f + i, t, 1);
    }
    for(int i = 1; i <= n; i ++) {
        Dinic.AddEdge(i ,n + i, 1);//牛拆點以後的創建的邊1 ~ 2 * n
        scanf("%d %d", &a, &b);
        for(int j = 0; j < a; j ++) {
            scanf("%d", &c);
            Dinic.AddEdge(n * 2 + c, i, 1);//食物與牛建邊
        }
        for(int j = 0; j < b; j ++) {
            scanf("%d", &c);
            Dinic.AddEdge(i + n, n * 2 + f + c, 1);//飲料與牛建邊
        }
    }
    printf("%d\n", Dinic.Maxflow());//模版最大流?
    return 0;
}
相關文章
相關標籤/搜索