【网络流+贪心】Homework

本文探讨了一个学生在两门课程间随机选择并完成作业的问题。通过贪心算法和网络流算法,分别求解了在最坏和最好情况下,学生能够完成的作业数量。文章详细介绍了如何使用单调队列和网络流来解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

Taro is a student of Ibaraki College of Prominent Computing. In this semester, he takes two courses, mathematics and informatics. After each class, the teacher may assign homework. Taro may be given multiple assignments in a single class, and each assignment may have a different deadline. Each assignment has a unique ID number.
Everyday after school, Taro completes at most one assignment as follows. first, he decides which course’s homework to do at random by flipping a coin. Let S be the set of all the unfinished assignments of the chosen course whose deadline has not yet passed. If S is empty, he plays a video game without doing any homework on that day even if there are unfinished assignments of the other course. Otherwise, with T ⊆ S being the set of assignments with the nearest deadline among S, he completes the one with the smallest assignment ID among T.
The number of assignments Taro will complete until the end of the semester depends on the result of coin flips. Given the schedule of homework assignments, your task is to compute the maximum and the minimum numbers of assignments Taro will complete.

输入

The input consists of a single test case in the following format.

n m
s1 t1
.
.
.
sn tn

The first line contains two integers n and m satisfying 1 ≤ m < n ≤ 400. n denotes the total number of assignments in this semester, and m denotes the number of assignments of the mathematics course (so the number of assignments of the informatics course is n − m).
Each assignment has a unique ID from 1 to n; assignments with IDs 1 through m are those of the mathematics course, and the rest are of the informatics course. The next n lines show the schedule of assignments. The i-th line of them contains two integers si and ti satisfying 1 ≤ si ≤ ti ≤ 400, which means that the assignment of ID i is given to Taro on the si-th day of the semester, and its deadline is the end of the ti-th day.

输出

In the first line, print the maximum number of assignments Taro will complete. In the second line, print the minimum number of assignments Taro will complete.

样例输入

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

样例输出

6
2


不得不说,日本人的英语真难懂.

题意很简单,就是你有两项作业,一个是数学,一个是信息学,以及布置时间和结束时间。你每天就做一项,然后是抛硬币选作业。假如说你数学做完了,信息学作业还没写,但是天意告诉你要学数学,于是乎你打起了游戏。

  • 完成的最多:
    知道起始时间,用贪心做,先做快结束的。单调队列维护。
  • 完成的最少:
    就是这天你数学作业写完了,信息学作业还没写,但是天意告诉你要学数学。建图:跑网络流

    sic->数学作业 f=1
    数学作业->天 f=1
    天->天 拆点 f=1
    天->信息作业 f=1
    信息作业->sink f=1

这就意味着如果这天你如果只有一项作业,那就不写
有两项 那就写一项。

  • 为什么拆点? 这样就限制了一天只写一份作业。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+7;
const int maxm=1e6+7;
int n,m,src,sink;
int head[maxn],tol=1,ans;
int cur[maxn],dep[maxn];
const int inf=0x3f3f3f3f;
struct Edge{int to,next,val;}e[maxm];
struct node{int s,t;}s[maxn];
void add(int u,int v,int f){
     tol++;
     e[tol].to=v;
     e[tol].next=head[u];
     e[tol].val=f;
     head[u]=tol;
}
bool bfs(int s,int t){
    queue<int>q;
    memset(dep,-1,sizeof(dep));
    q.push(s);
    dep[s]=0;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int v,i=head[now];i;i=e[i].next){
            v=e[i].to;
            if(dep[v]==-1&&e[i].val){
                dep[v]=dep[now]+1;
                if(v==t) return true;
                q.push(v);
            }
        }
    }
    return false;
}
int dfs(int x,int maxx){
    if(x==sink) return maxx;
    for(int& i=cur[x];i;i=e[i].next){
        if(dep[e[i].to]==dep[x]+1&&e[i].val){
            int flow=dfs(e[i].to,min(maxx,e[i].val));
            if(flow){
                e[i].val-=flow;
                e[i^1].val+=flow;
                return flow;
            }
        }
    }
    return 0;
}
void dinic(int s,int t){
  ans=0;
  while(bfs(s,t)){
    for(int i=0;i<=t;i++) cur[i]=head[i];
    while(int d=dfs(s,inf)) ans+=d;
  }
}
bool cmp(node a,node b)
{
    return a.s<b.s;
}
int main()
{
    int n,math;
    scanf("%d%d",&n,&math);
    src=0;
    sink=1201;
    for(int i=1;i<=math;i++){
        scanf("%d%d",&s[i].s,&s[i].t);
        add(src,i,1);
        add(i,src,0);
        for(int j=s[i].s;j<=s[i].t;j++){
            add(i,j+400,1);
            add(j+400,i,0);
        }
    }
    for(int i=1;i<=400;i++){
        add(i+400,i+800,1);
        add(i+800,i+400,0);
    }
    for(int i=math+1;i<=n;i++){
        scanf("%d%d",&s[i].s,&s[i].t);
        add(i,sink,1);
        add(sink,i,0);
        for(int j=s[i].s;j<=s[i].t;j++){
            add(j+800,i,1);
            add(i,j+800,0);
        }
    }
    priority_queue<int, vector<int>, greater<int> > Q;
    sort(s+1,s+n+1,cmp);
    int now=1,ans1=0;
    for(int i=1;i<=400;i++){
        while(now<=n&&i==s[now].s) {Q.push(s[now].t);now++;}
        if(!Q.empty()&&i<=Q.top()){Q.pop();ans1++;}
        while(!Q.empty()&&i>=Q.top()){Q.pop();}
    }
    dinic(src,sink);
    printf("%d\n",ans1);
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/smallocean/p/9602081.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值