1. 程式人生 > >網路流24題—— 試題庫問題

網路流24題—— 試題庫問題

題目描述

假設一個試題庫中有n道試題。每道試題都標明瞭所屬類別。同一道題可能有多個類別
屬性。現要從題庫中抽取m 道題組成試卷。並要求試卷包含指定型別的試題。試設計一個
滿足要求的組卷演算法。
程式設計任務:
對於給定的組卷要求,計算滿足要求的組卷方案。

輸入格式

由檔案input.txt提供輸入資料。檔案第1行有2個正整數k和n (2 <=k<= 20, k<=n<= 1000)
k 表示題庫中試題型別總數,n 表示題庫中試題總數。第2 行有k 個正整數,第i 個正整數
表示要選出的型別i 的題數。這k個數相加就是要選出的總題數m。接下來的n行給出了題
庫中每個試題的型別資訊。每行的第1 個正整數p表明該題可以屬於p類,接著的p個數是
該題所屬的型別號。

輸出格式

程式執行結束時,將組卷方案輸出到檔案output.txt 中。檔案第i 行輸出 “i:”後接類
型i的題號。如果有多個滿足要求的方案,只要輸出1 個方案。如果問題無解,則輸出“No Solution!”。

樣例輸入

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

樣例輸出

1: 1 6 8
2: 7 9 10
3: 2 3 4 5

這道題,應該算是二分圖匹配的變式吧?

先來試試二分圖匹配的建圖方法!
看做兩個集合,取名無力的我選擇讓他們一個叫A集,一個叫B集!
A集表示需要的型別,B集表示題目

醬紫,就變成了二分圖匹配的問題啦!
從A集出發有很多很多條邊到B集。

用最原始的方法
假設型別一需要3道題,那麼我們可以看做存在三個型別一,然後每個型別一需要一道題
對於所有的型別需要的題數都同理操作,就是正正經經的二分圖匹配問題啦!

具體說說這個怎麼建圖:
假設,型別i需要x[i]道題目
首先,……超級源點….超級匯點
然後,把x[i]個型別i和超級源點連起來,令其容量為1
再然後,把題目和超級匯點連起來,令容量為1
接著(然後用的太多了,換個詞),把型別和題目按照題目連線起來
最後,跑dinic

模仿金星老師:完美~

不過我沒寫過,大概會TLE?唔,無聊的時候可以寫寫(捂臉)
來稍微改動改動!體現網路流的優越性(霧)

咱們來把型別i的x[i]個點合併起來,令超級源點到型別i所代表的點的容量為i
然後,就跑dinic
和之前的某道題一樣喲,某條邊的flow==1就代表被匹配到了!
唔,順便說一句。這樣跑出來的最大流的值如果比需要的題目數量還少,就代表木有成功咯,需要輸出”No Solution!”

然後就沒有然後啦!和以前一樣搞就可以了的說~

唔,溫馨提示:注意資料範圍
因為我RE了!(捂臉)

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#define INF 1e8
using namespace std;

const int maxn=1505;
int n,m,s,t;
struct Edge{int from,to,cap,flow;};
vector<Edge>edges(20000);
vector<int>G[maxn];
int d[maxn];
bool vis[maxn];

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

int DFS(int x,int a){
    int flow=0,f;
    if(x==t || a==0) return a;
    for(int i=0;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;
            edges[G[x][i]^1].flow-=f;
            a-=f;
            flow+=f;
            if(a==0) break;
        }
    }
    return flow;
}

bool BFS(){
    queue<int>q;
    memset(vis,0,sizeof(vis));
    d[s]=1;vis[s]=true;q.push(s);
    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){
                d[e.to]=d[x]+1;
                vis[e.to]=true;
                q.push(e.to);
            }
        }
    }
    return vis[t];
}

int dinic(){
    int flow=0;
    while(BFS())
        flow+=DFS(s,INF);
    return flow;
}

int main(){
    int sum=0;
    scanf("%d%d",&n,&m);
    s=0;t=n+m+1;
    for(int c,i=1;i<=n;i++){
        scanf("%d",&c);
        AddEdge(s,i,c);
        sum+=c;
    }
    for(int a,k,i=1;i<=m;i++){
        scanf("%d",&k);
        for(int j=1;j<=k;j++){
            scanf("%d",&a);
            AddEdge(a,i+n,1);
        }
    }
    for(int i=n+1;i<=m;i++) AddEdge(i,t,1);
    if(dinic()!=sum){puts("No Solution!");}
    else{
        for(int i=1;i<=n;i++){
            printf("%d:",i);
            for(int j=0;j<G[i].size();j++){
                Edge e=edges[G[i][j]];
                if(e.to!=t && e.flow==1){
                    printf(" %d",e.to-n);
                }
            }
            printf("\n");
        }
    }
    return 0;
}