網絡流與線性規劃24題05圓桌問題

問題描述:
假設有來自n 個不同單位的代表參加一次國際會議。每個單位的代表數分別爲
r i n i , =1,2,, 。會議餐廳共有m張餐桌,每張餐桌可容納c (i 1,2, ,m) i =  個代表就餐。
爲了使代表們充分交流,希望從同一個單位來的代表不在同一個餐桌就餐。試設計一個算法,
給出滿足要求的代表就餐方案。
編程任務:
對於給定的代表數和餐桌數以及餐桌容量,編程計算滿足要求的代表就餐方案。
數據輸入:
由文件input.txt提供輸入數據。文件第1行有2 個正整數m和n,m表示單位數,n表
示餐桌數,1<=m<=150, 1<=n<=270。文件第2 行有m個正整數,分別表示每個單位的代表
數。文件第3 行有n個正整數,分別表示每個餐桌的容量。
結果輸出:
程序運行結束時,將代表就餐方案輸出到文件output.txt 中。如果問題有解,在文件第
1 行輸出1,否則輸出0。接下來的m行給出每個單位代表的就餐桌號。如果有多個滿足要
求的方案,只要輸出1 個方案。

輸入示例:

4 5
4 5 3 5
3 5 2 6 4

輸出示例:

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

分析:

啊哈哈哈,這是嚴格意義上本人完全自己解出來的網絡流題目,沒有參考任何的資料和報告。小激動一下。言歸正傳,剛看到這題第一個感覺就是二分圖,然後根據題意建模,

一個單位的人只能去不同的桌子,表示任意一個單位到任意一個桌子的路徑容量是1,然後源點到所有不同的單位的容量是單位人數,所有桌子到匯點的容量是桌子人數。求出最大流看是否等於總人數,如果相等就有解,然後從每個單位到每個桌子如果有流量則輸出。有木有很簡單。

後來看了大牛的分析,才知道這道題目是二分圖多重匹配問題。專業的模型說法是對於一個二分圖,每個頂點可以有多個匹配頂點,稱這類問題爲二分圖多重匹配問題。X,Y集合之間的邊容量全部是1,保證兩個點只能匹配一次(一個餐桌上只能有一個單位的一個人),源匯的連邊限制了每個點匹配的個數。求出網絡最大流,如果流量等於X集合所有點與S邊容量之和,那麼則說明X集合每個點都有完備的多重匹配。

和我的想法不謀而合啊。

另外還有貪心的解法,由於是網絡流專題,這裏不贅述了,請自行百度。

代碼應該很清晰了,建圖和求最大流的過程,感覺沒什麼好加註釋的了。

代碼:

#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 430;
const int INF = 1<<30;
int s,t;
struct edge{
    int from,to,cap,flow;
    edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d)
    {}
};
bool visit[maxn];
vector<int> g[maxn];
vector<edge> edges;
int d[maxn];
int cur[maxn];
bool BFS()
{
    memset(visit,false,sizeof(visit));
    d[s]=0;
    queue<int> q;
    q.push(s);
    visit[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(!visit[e.to]&&e.cap>e.flow){
                d[e.to]=d[x]+1;
                visit[e.to]=true;
                q.push(e.to);
            }
        }
    }
    return visit[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[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
            e.flow+=f;
            flow+=f;
            edges[g[x][i]^1].flow-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}

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);
}
int main()
{
    int n,m;
    scanf("%d%d",&m,&n);
    s=0;t=m+n+1;
    int temp;
    int sum=0;
    int max=0;
    for(int i=1;i<=m;i++){
        scanf("%d",&temp);
        sum+=temp;
        max=temp>max?temp:max;
        addedge(s,i,temp);
    }
    for(int i=m+1;i<=n+m;i++){
        scanf("%d",&temp);
        addedge(i,t,temp);
    }
    if(max>n) {printf("0\n");return 0;}//實際測試數據中沒有用
    for(int i=1;i<=m;i++)
        for(int j=m+1;j<=m+n;j++)
            addedge(i,j,1);

    int flow=0;
    while(BFS()){
        memset(cur,0,sizeof(cur));
        flow+=DFS(s,INF);
    }
    if(flow==sum){
        printf("1\n");
        for(int i=1;i<=m;i++){
            for(int j=0;j<g[i].size();j++){
                edge &e=edges[g[i][j]];
                if(e.flow==1) printf("%d ",e.to-m);
            }
            printf("\n");
        }
    }else printf("0\n");

    return 0;
}


 

發佈了34 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章