网络流与线性规划24题07试题库问题

问题描述:
假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别
属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个
满足要求的组卷算法。
编程任务:
对于给定的组卷要求,计算满足要求的组卷方案。
数据输入:
由文件input.txt提供输入数据。文件第1行有2个正整数n和k (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                          1: 1 6 8
3 3 4                         2: 7 9 10
2 1 2                         3: 2 3 4 5
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

分析:

这题有点水,二分图多重匹配。所有题目为X点,所有类型为Y点,建立源点S,汇点T

S连接所有的X点,容量为1,表示每题只能选择一次。所有的Y点连接T点,容量为每个类型的需求题数。

对于每题X能属于不同的Y的类型,就连接对应的X,Y点,容量为1,其实这里的容量1还是无穷都无所谓的,因为源汇点已经限制了容量。

然后求一次最大流,如果最大流等于题目合,就有解。对于所有从X出发指向Y的边,流量为1则为一个可行解。否则无解输出No Solution!。

代码应该也没什么要解释的。

代码:

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

const int maxn = 1001;
const int INF = 1<<30;
struct edge{
    int from,to,cap,flow;
    edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d)
    {}
};
vector<int> g[maxn];
vector<edge> edges;
bool visit[maxn];
int d[maxn];
int cur[maxn];
int s,t;
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(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){
                visit[e.to]=true;
                d[e.to]=d[x]+1;
                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){
            flow+=f;
            a-=f;
            e.flow+=f;
            edges[g[x][i]^1].flow-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int main()
{
    int k,n;
    scanf("%d%d",&k,&n);
    s=0;t=k+n+1;
    int cap,sum=0;
    for(int i=1;i<=k;i++){
        scanf("%d",&cap);
        sum+=cap;
        addedge(i,t,cap);
    }
    getchar();
    for(int i=k+1;i<=k+n;i++){
        int res=0,c;
        while((c=getchar())!='\n'){
            if(c==' ') {addedge(i,res,1);res=0;}
            else res=res*10+c-'0';
        }
        addedge(i,res,1);
        addedge(s,i,1);
    }

    int flow=0;
    while(BFS()){
        memset(cur,0,sizeof(cur));
        flow+=DFS(s,INF);
    }
    if(flow!=sum) printf("“No Solution!\n");
    else{
        for(int i=1;i<=k;i++){
            printf("%d:",i);
            for(int j=0;j<g[i].size();j++){
                edge &e=edges[g[i][j]^1];
                if(e.flow==1) printf(" %d",e.from-k);
            }
            printf("\n");
        }
    }
    return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章