程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> poj2112,最大流,最優擠奶方案

poj2112,最大流,最優擠奶方案

編輯:C++入門知識

按圖論列表上來說是基礎題。

這道題是省賽之前過的,現在想再拿出來總結一下,感覺這個類型的題很經典。


題意不敘述了,就是有奶牛和機器,每台奶牛分配一個機器,

牛與牛、牛與機器、機器與機器之間都有一距離,求分配後的最大距離的最小值。


一開始沒明白啥叫“最大距離的最小值”,就是C頭奶牛、K個擠奶器,C頭奶牛若想到全部的擠奶器那裡去需要一定的距離,

C頭奶牛當中某一頭奶牛需要走的距離最大那這個距離便為最大值,要使這個最大值最小。(DT的題意)

這樣子二分就好了,(又是二分,泥垢了),若根據mid建圖後的最大流>=C,那這個便是成功的。


有一堆點位於X,一堆點位於Y,若試著建立從X到Y的某種關系,(比如距離、權值),加入超級源點與匯點S、T並建立相應權的邊後

肯定能夠使得X的點和Y的點分別屬於集合S、T(這也是最小割的思想)。

ps:二分輸出的技巧如我的代碼 if(ans>=mid) R = mid; cout<


廢話了比較多,僅是自己身為一個弱渣的小提醒。附個代碼。


#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int INF = 0x3c3c3c3c;

const int maxn = 500 + 10; //結點最多數目
struct Edge{ //代表一條from->to容量為cap,流量為flow的弧
    int from, to, cap, flow;
};

struct Dinic{
    int n, m, s, t;   //結點數,邊數(包括反向弧), 源點、匯點號
    vector edges; //邊表  edge[e]與edge[e^1]互為反向弧
    vector G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

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

    bool BFS(){
        memset(vis, 0, sizeof(vis));
        queue Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        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] = 1;
                    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;
        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 s, int t){
        this->s = s;  this->t = t;
        int flow = 0;
        while(BFS()){
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        return flow;
    }
};
int dis[500][500];
int main()
{
    //freopen("in.txt", "r", stdin);
    int K, C, M;
    while(scanf("%d %d %d", &K, &C, &M) == 3){
        int i, j, k, l, a;
        int sum = K + C;
        for(i = 1;i <= sum;i++){
            for(j = 1;j <= sum;j++){
                scanf("%d", &a);
                if(i==j) { dis[i][j] = 0; continue; }
                if(a == 0) dis[i][j] = INF;
                else dis[i][j] = a;
            }
        }

        for(k = 1;k <= sum;k++){
            for(i = 1;i <= sum;i++){
                for(j = 1;j <= sum;j++){
                    if(dis[i][j] > dis[i][k]+dis[k][j])
                        dis[i][j] = dis[i][k] + dis[k][j];
                }
            }
        }

        int L = 1, R = 40000;
        while(L < R){
            int mid =(L+R)/2;
            Dinic test;
            for(i = 1;i <= K;i++){
                for(j = K+1;j <= sum;j++){
                    if(dis[i][j]<=mid) test.AddEdge(i,j,1);
                }
            }
            for(i = 1;i <= K;i++) test.AddEdge(0,i,M);
            for(i = K+1;i <= sum;i++) test.AddEdge(i,sum+1,1);
            int ans = test.Maxflow(0, sum+1);
            if(ans>=C) {  // why bi_search? it's up
                R = mid;
            }
            else L = mid+1;
        }
        printf("%d\n", R);
    }
    return 0;
}


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved