zoukankan      html  css  js  c++  java
  • [日常训练]选课

    Description

    小$G$非常喜欢学习,热衷于刷$GPA$。新的学期开始,他又要开始挑选课程,以便刷分了。
    他的课业计划中共包含$n$项课程,每项课程都需要在$m$周中的某一周完成。课程与周数都从$1$开始编号。
    一些课程有前置课程,对于所有的$i(1;leq;i;leq;k)$,$a_i$是$b_i$的前置课程。也就是修完$a_i$才能修$b_i$。
    相同的课程在不同周可能会由不同教授授课,不同教授会影响小$G$在这门课上的分数。
    我们用一个数组$x_{i,j}$来描述这个信息,对于每项课程$i$和周数$j$,$x_{i,j}$表示在第$j$周修第$i$门课所能得到的分数。如果$x_{i,j}=−1$则说明那周不能修这门课。
    一周中可以修多门课,而一门课需要用一整周的时间才算修完。
    请帮助小$G$修完所有课程,并使得他得到分数的平均值最大吧。

    Input

    第一行三个整数$n,m,k$,表示课程数、总周数与前置课程关系数。
    接下来$n$行,每行$m$个整数,第$i$行第$j$个数表示$x_{i,j}$。
    接下来$k$行,每行包含两个整数$a_i,b_i$。

    Output

    输出一个实数,表示所能得到的$n$门课程分数平均值的最大值。答案保留两位小数。

    Sample Input

    4 5 4
    20 -1 100 -1 -1
    100 30 -1 -1 -1
    100 -1 30 20 40
    100 30 40 50 20
    1 2
    1 3
    2 4
    3 4

    Sample Output

    32.50

    HINT

    $1;leq;n,m;leq;100,0;leq;k;leq;100,−1;leq;x_{i,j};leq;100,1;leq;a_i,b_i;leq;n$.

    Solution

    总数不变,平均值最大即总和最大,考虑用网络流求解.

    先将每个课程$i$按完成的的日期$d$拆成点$<i,d>$.

    从$s$向$<i,0>$连一条容量为$+infty$的有向边,

    从$<i,m>$向$t$连一条容量为$+infty$的有向边,

    从$<i,d>$向$<i,d+1>$连一条容量为$100-x_{i,d+1}$的有向边($din[0,m)$),

    从$<a_i,d>$向$<b_i,d+1>$连一条容量为$+infty$的有向边($din[0,m)$).

    跑最小割$mincut$,答案为$frac{100n-mincut}{n}$.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 105
    #define N 10105
    #define M 40405
    #define INF 1000000000
    using namespace std;
    struct graph{
        int nxt,to,f;
    }e[M];
    int x[K][K],g[N],dep[N],n,m,k,s,t,cnt;
    queue<int> q; 
    inline void addedge(int x,int y,int f){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    }
    inline void adde(int x,int y,int f){
        addedge(x,y,f);addedge(y,x,0);
    }
    inline bool bfs(int u){
        memset(dep,0,sizeof(dep));
        dep[u]=1;q.push(u);
        while(!q.empty()){
            u=q.front();q.pop();
            for(int i=g[u];i;i=e[i].nxt)
                if(e[i].f>0&&!dep[e[i].to]){
                    q.push(e[i].to);
                    dep[e[i].to]=dep[u]+1;
                }
        }
        return dep[t];
    }
    inline int dfs(int u,int f){
        int ret=0;
        if(u==t) return f;
        for(int i=g[u],d;i&&f;i=e[i].nxt)
            if(e[i].f>0&&dep[e[i].to]>dep[u]){
                d=dfs(e[i].to,min(f,e[i].f));
                ret+=d;f-=d;e[i].f-=d;e[i^1].f+=d;
            }
        if(!ret) dep[u]=-1;
        return ret;
    }
    inline int dinic(){
        int ret=0;
        while(true){
            if(!bfs(s)) return ret;
            ret+=dfs(s,INF);
        }
    }
    inline void Aireen(){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;++i)
            for(int j=0;j<=m;++j)
                x[i][j]=++cnt;
        s=++cnt;t=++cnt;
        cnt=1;
        for(int i=1;i<=n;++i){
            adde(s,x[i][0],INF);
            adde(x[i][m],t,INF);
        }
        for(int i=1,y;i<=n;++i)
            for(int j=0;j<m;++j){
                scanf("%d",&y);
                if(y<0) adde(x[i][j],x[i][j+1],INF);
                else adde(x[i][j],x[i][j+1],100-y);
            }
        for(int i=1,a,b;i<=k;++i){
            scanf("%d%d",&a,&b);
            for(int j=0;j<m;++j)
                adde(x[a][j],x[b][j+1],INF);
        }
        printf("%.2lf
    ",100.0-(double)(dinic())/(double)(n));
    }
    int main(){
        freopen("select.in","r",stdin);
        freopen("select.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Hive 复杂数据类型的使用
    Hive 函数之内置运算符
    Hive中Join的类型和用法
    Hive 文件格式 & Hive操作(外部表、内部表、区、桶、视图、索引、join用法、内置操作符与函数、复合类型、用户自定义函数UDF、查询优化和权限控制)
    初步认识Hive
    Hadoop之MapReduce
    我理解中的Hadoop HDFS分布式文件系统
    Hadoop环境搭建 (伪分布式搭建)
    Hadoop(初始Hadoop)
    【数据库】MySQL 从安装到命令
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6269026.html
Copyright © 2011-2022 走看看