Codechef Course Selection

Home » Practice(Hard) » Course Selection

Course Selection Problem Code: RINSubmit

https://www.codechef.com/problems/RIN

All submissions for this problem are available.

Read problems statements in Mandarin Chineseand Russian.

Rin is attending a university.

She has M semesters to finish her program, and that program has N required courses. Each course must be taken in exactly one of the semesters.

Some courses have prerequisites: for each i from 1 to K, she must take course A[i]before course B[i].

The same course may be taught by different professors in different semesters, and how well she does will depend on which professor teaches her. Additionally, some courses may not be taught every semester.

We are given an array X representing this information. For each course i and each semester j, X[i][j] = -1 if course i is not taught in semester j. Otherwise, X[i][j] will be an integer between 0 and 100: the expected score Rin will get if she takes course i in semester j.

Rin may take any number of courses per semester, including none, as long as they are taught that semester and she has already taken any required prerequisite courses.

Help Rin to find the maximal average score she can get over her whole program.

Input

The first line contain 3 integers: N, M and K.

This is followed by N lines, each containing M integers. The jth integer on the ith line represents the value of X[i][j].

This is followed by K lines, each containing two integers: A[i] and B[i].

Output

Output one real number: the maximal average score, rounded to 2 digits after the decimal point.

Constraints

  • 1 ≤ M, N ≤ 100
  • 0 ≤ K ≤ 100
  • -1 ≤ X[i][j] ≤ 100
  • 1 ≤ A[i], B[i] ≤ N
  • For each i, A[i] ≠ B[i].
  • For different i and j, (A[i], B[i]) ≠ (A[j], B[j]).
  • We guarantee there exists a way to take these N courses in M semesters.

Subtasks

Subtask 1: (20 Points) A course can have at most 1 pre request course.

Subtask 2: (80 Points) Refer to constraints above

Example

Input 1:
3 2 2
70 100
100 80
100 90
1 2
1 3

Output 1:
80.00

Input 2:
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

Output 2:
32.50

Explanation

Example case 1

The only way she can finish these 3 courses is: take course 1 in the first semester, then take courses 2 and 3 in the second semester. The average score is (70 + 80 + 90) / 3 = 80.00.

Example case 2

The optimal solution is: take course 1 in semester 1, course 2 in semester 2, course 3 in semester 3 and course 4 in semester 4.

n个课程要在m个学期里完成,

有k个依赖关系a,b ,表示a课程必须在b课程之前

每个课程在每个学期有相应得分

-1 表示本学期不开设此课程

问 最大的课程得分平均值

最大得分转化为最小扣分

对下面这张图跑最小割,ans=n*100-最小割

解释:Step 3 :防止所有边都割在了源点向第一学期

Step 4 :  inf边一定不会被割,a是b的前置课程,如果b的边割在了a之前,图可以通过inf边联通,不符合最小割

求助大佬,为什么以下建图方式不对

#include<queue>
#include<cstdio>
#include<algorithm>
#define inf 0x7fffffff
#define N 10101
#define M 50000
using namespace std;
queue<int>q;
int n,m,k,src,decc,tmp;
int front[N],to[M],nxt[M],tot=1;
int lev[N],cur[N],cap[M];
int score[101][101];
bool f[101];
//#define turn((i),(j)) ((i)-1)*(m+1)+(j)
int turn(int i,int j)
{
    return (i-1)*m+j;
}
void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; cap[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
bool bfs()
{
    while(!q.empty()) q.pop();
    for(int i=src;i<=decc;i++) cur[i]=front[i],lev[i]=-1;
    lev[src]=0; q.push(src);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        for(int i=front[now];i;i=nxt[i])
        {
            if(lev[to[i]]==-1&&cap[i]>0)
            {
                lev[to[i]]=lev[now]+1;
                if(to[i]==decc) return true;
                q.push(to[i]);
            }
        }
    }
    return false;
}
int dinic(int now,int flow)
{
    if(now==decc) return flow;
    int rest=0,delta;
    for(int &i=cur[now];i;i=nxt[i])
    {
        if(lev[to[i]]>lev[now]&&cap[i]>0)
        {
            delta=dinic(to[i],min(flow-rest,cap[i]));
            if(delta)
            {
                cap[i]-=delta; cap[i^1]+=delta;
                rest+=delta; if(rest==flow) break;
            }
        }
    }
    if(rest!=flow) lev[now]=-1;
    return rest;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int x; decc=n*m+1;
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      scanf("%d",&score[i][j]);
    for(int i=1;i<=n;i++)   add(turn(i,m),decc,inf);
    int a,b;
    while(k--)
    {
        scanf("%d%d",&a,&b);
        for(int i=1;i<m;i++) add(turn(a,i),turn(b,i+1),inf);
        f[b]=true;
    }
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      if(j==1)
       {
             if(f[i]) add(src,turn(i,1),inf);
             else  add(src,turn(i,1),score[i][j]==-1 ? inf : 100-score[i][j]);
       }
      else add(turn(i,j-1),turn(i,j),score[i][j]==-1 ? inf : 100-score[i][j]);
    while(bfs())
     tmp+=dinic(src,inf);
    tmp=n*100-tmp;
    printf("%.2lf",double(tmp)/n);
}

错误建图代码

#include<queue>
#include<cstdio>
#include<algorithm>
#define inf 0x7fffffff
#define N 10101
#define M 50000
using namespace std;
queue<int>q;
int n,m,k,src,decc,tmp;
int front[N],to[M],nxt[M],tot=1;
int lev[N],cur[N],cap[M];
//#define turn((i),(j)) ((i)-1)*(m+1)+(j)
int turn(int i,int j)
{
    return (i-1)*(m+1)+j;
}
void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; cap[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
bool bfs()
{
    while(!q.empty()) q.pop();
    for(int i=src;i<=decc;i++) cur[i]=front[i],lev[i]=-1;
    lev[src]=0; q.push(src);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        for(int i=front[now];i;i=nxt[i])
        {
            if(lev[to[i]]==-1&&cap[i]>0)
            {
                lev[to[i]]=lev[now]+1;
                if(to[i]==decc) return true;
                q.push(to[i]);
            }
        }
    }
    return false;
}
int dinic(int now,int flow)
{
    if(now==decc) return flow;
    int rest=0,delta;
    for(int &i=cur[now];i;i=nxt[i])
    {
        if(lev[to[i]]>lev[now]&&cap[i]>0)
        {
            delta=dinic(to[i],min(flow-rest,cap[i]));
            if(delta)
            {
                cap[i]-=delta; cap[i^1]+=delta;
                rest+=delta; if(rest==flow) break;
            }
        }
    }
    if(rest!=flow) lev[now]=-1;
    return rest;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int x; decc=n*(m+1)+1;
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      {
            scanf("%d",&x);
          if(x==-1) x=inf;
          else x=100-x;
          add(turn(i,j),turn(i,j+1),x);
      }
    for(int i=1;i<=n;i++)
     add(0,turn(i,1),inf),
     add(turn(i,m+1),decc,inf);
    int a,b;
    while(k--)
    {
        scanf("%d%d",&a,&b);
        for(int i=1;i<=m;i++) add(turn(a,i),turn(b,i+1),inf);
    }
    while(bfs())
     tmp+=dinic(src,inf);
    tmp=n*100-tmp;
    printf("%.2lf",double(tmp)/n);
} 

时间: 2024-08-25 06:19:22

Codechef Course Selection的相关文章

Codechef RIN 「Codechef14DEC」Course Selection 最小割离散变量模型

问题描述 提供中文版本好评,一直以为 Rin 是题目名字... pdf submit 题解 参考了 东营市胜利第一中学姜志豪 的<网络流的一些建模方法>(2016年信息学奥林匹克中国国家队候选队员论文) 读了之后很有感触,这里节选一段话: 最小割模型的本质是将点的集合 \(V\) 划分为两个点集 \(S,T\) ,使得 \(S \in S,T \in T\) ,且 \(S∩T=?\) 之前对最小割中边权为 \(INF\) 的边,一直理解为不允许被割,现在从另一个角度来认识,就是保证这条边所联通

codechef : Marbles 题解

Rohit dreams he is in a shop with an infinite amount of marbles. He is allowed to select n marbles. There are marbles of k different colors. From each color there are also infinitely many marbles. Rohit wants to have at least one marble of each color

CSS3选择器 ::selection选择器

"::selection"伪元素是用来匹配突出显示的文本(用鼠标选择文本时的文本).浏览器默认情况下,用鼠标选择网页文本是以"深蓝的背景,白色的字体"显示的,效果如下图所示: 从上图中可以看出,用鼠标选中"专注IT.互联网技术"."纯干货.学以致用"."没错.这是免费的"这三行文本中,默认显示样式为:蓝色背景.白色文本. 有的时候设计要求,不使用上图那种浏览器默认的突出文本效果,需要一个与众不同的效果,此时

CSS3特殊伪类::selection改变页面选中文字的样式

一般在网页上面,选中文字的时候,文字的样式是会改变的,当然,样式也都是千篇一律的浏览器的默认样式,蓝底白字,偶然看到有些网页上面当文字选中的时候会有不一样的样式,当时就很是好奇,后来才慢慢发现是css的一个伪类::selection ::selection是一个CSS3选择器(这也告诉这我们CSS3必须要去熟悉,这玩意确实可以弄出很多意想不到的好效果.) 兼容性:IE9+,Chrome,Opera,Safari,Firefox…(也可以去查看)caniuse.com#search=::selec

理解Selection对象

Selection对象的属性如下: var selection = window.getSelection(); console.log(selection); 通过上面的代码在控制台查看: anchorNode: {node} 节点: 包含了用户选取内容的起点的节点. anchorOffset {int} 整型值: 用户选取内容的起点与anchorNode属性值所返回的节点的起点之间的距离. focusNode {node} 节点: 包含了用户选取内容的终点的节点. focusOffset {

CodeChef FNCS (分块+树状数组)

题目:https://www.codechef.com/problems/FNCS 题解: 我们知道要求区间和的时候,我们用前缀和去优化.这里也是一样,我们要求第 l 个函数到第 r 个函数 [l, r] 的函数和,那么我们可以用 sum[r] - sum[l-1] 来求得. 由于这个数据量有点大,所以我们将函数分块. 例如样例: 1 3 有5个函数,那么我们分成3块.{ [1 3] , [2 5] }, { [4 5], [3 5] }, { [1 2] }.每一块对应都有一个sum ,这时如

codechef营养题 第三弹

第三弾が始まる! codechef problems 第三弹 一.Motorbike Racing 题面 It's time for the annual exciting Motorbike Race in Byteland. There are N motorcyclists taking part in the competition. Johnny is watching the race. At the present moment (time 0), Johnny has taken

codechef 营养题 第一弹

第一弾が始まる! 定期更新しない! 来源:http://wenku.baidu.com/link?url=XOJLwfgMsZp_9nhAK15591XFRgZl7f7_x7wtZ5_3T2peHh5XXoERDanUcdxw08SmRj1a5VY1o7jpW1xYv_V1kuYao1Pg4yKdfG4MfNsNAEa codechef problems 第一弹 一.Authentication Failed原题题面Several days ago Chef decided to registe

bzoj4260: Codechef REBXOR

求异或maxmin一般用trie (二进制式的trie).query中找的是满足((x>>i)&1)^A=1,那么A=((x>>i)&1)^1:maxx=max(sumx,sumi)(i=[1,x]).(YY一下异或的性质 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #def