洛谷_2055 假期的宿舍

本文介绍了一种使用最大流算法解决学生住宿分配问题的方法。通过构建合适的图模型,并运用最大流算法,可以判断是否有足够的床位供所有学生使用。

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

题意

有几个同学要来盼望在学校里的同学,他们希望他们和学校里的同学都有床睡,其中一个人只能睡他认识的人的床或自己的床。现在给出每个同学是否在校生和是否回家的情况,以及它们认识的情况,求出它们能否全部人都有床睡。

思路

这道题构好图然后跑一边最大流。让有床的人和汇点连接,需要床的人和源点连接,然后他们如果互相认识就让他们连接。

代码

#include<cstdio>
#include<cstring>
#include<queue>
#define min(a,b) a<b?a:b
using namespace std;
int tot,t,n,S,T,x,head[101],d[101],f,ans,sum;bool a[51];
struct node{
    int to,next,v;
}e[1001];
void add(int x,int y)
{
    e[++tot].to=y;e[tot].next=head[x];e[tot].v=1;
    head[x]=tot;
    e[++tot].to=x;e[tot].next=head[y];e[tot].v=0;
    head[y]=tot;
}
bool bfs()
{
    memset(d,0,sizeof(d));
    int v;
    queue<int>q;
    d[S]=1;q.push(S);
    while (q.size())
    {
        v=q.front();q.pop();
        for (int i=head[v];i!=-1;i=e[i].next)
        {
            int y=e[i].to;
            if (d[y]==0&&e[i].v)
            {
                d[y]=d[v]+1;
                q.push(y);
                if (y==T) return 1;
            }
        }
    }
    return 0;
}
int dfs(int k,int flow)
{
    if (k==T) return flow;
    int rest=0,w;
    for (int i=head[k];i!=-1;i=e[i].next)
    {
        if (e[i].v&&d[k]+1==d[e[i].to])
        {
            w=dfs(e[i].to,min(e[i].v,flow-rest));
            if (!w) d[e[i].to]=0;
            e[i].v-=w;
            e[i^1].v+=w;
            rest+=w;
        }
    }
    return rest;
}
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        memset(head,-1,sizeof(head));
        ans=sum=0;
        tot=1;
        scanf("%d",&n);
        S=0;T=2*n+1;
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if (a[i]) add(i+n,T);//在校生有床就和汇点连接
        }
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(!x||!a[i]) 
            {
                add(S,i);//需要床的
                ans++;//记录需要床的人数
            }
        }
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                scanf("%d",&x);
                if (x||i==j) add(i,j+n);//相互认识还有睡自己床的
            }
        }
        while (bfs())
            while (f=dfs(S,2147483647)) sum+=f;//求出最大流
        if (sum==ans) printf("^_^\n");//判断是否够床
        else printf("T_T\n");
    }
}
<think>嗯,用户需要解决洛谷上的AT_abc161_b问题,我得先找到这个题目的具体内容。首先,可能用户没有提供题目描述,所以我要根据题号来推测。AT_abc161_b通常对应的是AtCoder Beginner Contest 161的B题。常见的B题可能涉及数组操作、条件判断等基础算法。 首先,我应该回忆或查找这个题目的具体要求。比如,假设题目是关于选择满足条件的元素,可能需要计算平均值,或者某些比例。例如,可能需要从数组中选择前K个元素,或者满足某个条件的最小数量。 然后,根据用户提供的引用内容,虽然引用中提到了其他问题如AT_abc360的几个题目,但可能没有直接相关的。但用户提到的是AT_abc161_b,所以需要独立分析。这时候,正确的做法是参考常见的解题思路,比如排序、遍历、条件判断。 例如,可能的题目是:给定N个物品,每个物品有一个分数,需要选出至少多少个物品,使得它们的总分占总分的至少1/(4M),其中M是某个参数?或者类似的比例问题。 接下来,解题步骤可能包括: 1. 计算总分。 2. 确定每个被选元素需要满足的最小值(比如,分数必须大于等于总分的1/(4M))。 3. 排序数组,选择满足条件的元素数量是否足够。 但可能更准确的是,题目类似于:给定N个数,选择至少K个,使得每个选中的数大于等于总和的1/(4K)或其他比例。或者,可能要求的是选出前M个数,每个数必须大于等于总和的1/(4M)倍。 例如,假设题目是:有N个候选,每个候选有得票数,需要选出所有得票数大于等于总票数的1/(4M)的候选,如果不够M个则输出多少? 这时候,解题思路是: - 计算总票数sum。 - 确定阈值threshold = sum / (4*M) - 统计有多少个候选的票数 >= threshold - 如果统计的数量 >= M,则输出M,否则输出实际数量。 但需要确认题目的准确条件。例如,是否有四舍五入的问题,或者是否必须严格大于等。这时候,可能需要用浮点数处理或者整数运算避免误差。 假设题目是:总共有M个奖项,每个奖项需要选出一个票数至少为总票数的1/(4M)的候选,问最多能选出多少个符合条件的候选。如果候选数不足M,则输出候选数,否则输出M。 或者,题目可能需要将所有选中的候选按照票数排序,选择前M个,但每个都必须满足条件。例如,必须至少有M个候选满足票数 >= sum/(4M),否则无法满足条件,输出0或相关结果。 这时候,正确的步骤是: 1. 计算总票数sum。 2. 计算每个候选需要满足的最小值:threshold = sum / (4*M) 3. 统计满足条件的候选数cnt。 4. 如果cnt >= M,则输出M,否则输出cnt。 但可能存在特殊情况,例如sum可能无法被4*M整除,这时候是否需要向上取整或者如何处理?例如,使用浮点数比较,或者将条件转化为4*M*a_i >= sum,以避免除法带来的精度问题。 例如,题目中的条件可能是每个选中的a_i必须满足a_i >= sum/(4*M)。由于除法可能导致小数,处理时可能需要用乘法判断:a_i * 4*M >= sum。这样可以避免浮点运算的不精确。 因此,正确的做法是:遍历所有a_i,统计满足a_i *4*M >= sum的数量cnt。然后比较cnt和M,如果cnt >= M,则输出M,否则输出cnt。 现在需要验证这个思路是否正确。例如,假设sum=100,M=5,那么threshold=100/(4*5)=5。每个a_i需要>=5。如果总共有6个候选满足,则输出5。如果只有3个满足,则输出3。 这样的思路应该是正确的。此时,编写代码的步骤是读取N和M,读取数组,计算sum,然后遍历数组统计符合条件的数量,最后输出min(cnt, M)。 但需要注意可能的边界情况,例如sum=0的情况,或者所有a_i都为0的情况,此时如何处理?例如,当sum=0时,每个a_i也必须是0,所以条件a_i*4*M >=0是成立的,此时如果M>0,则输出min(cnt, M),但可能题目中的sum不会为0,或者有相应的处理方式。 另外,在代码实现时,计算sum的时候需要使用足够大的数据类型,避免溢出,比如使用long long类型。 综上,解题思路应该是正确的。然后根据这个思路写出对应的代码,例如在C++中: #include <iostream> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; vector<int> A(N); long long sum = 0; for (int i = 0; i < N; ++i) { cin >> A[i]; sum += A[i]; } int cnt = 0; for (int a : A) { if (a * 4 * M >= sum) { cnt++; } } cout << min(cnt, M) << endl; return 0; } 这样就能正确统计满足条件的候选数量,并输出结果。同时,避免了浮点运算的精度问题,使用整数运算更可靠。 此外,需要测试一些案例。例如: 样例输入1: 3 1 5 5 5 sum=15, threshold=15/(4*1)=3.75 → 每个元素是否>=3.75?都是5,满足。所以cnt=3,输出min(3,1)=1. 样例输入2: 5 2 8 3 4 5 10 sum=30. threshold=30/(4*2)=3.75. 满足的元素是8,5,10 → cnt=3. 输出min(3,2)=2. 这样代码应该能正确处理这些情况。 因此,用户的问题的解题思路应该是正确的,而代码部分也应当如此。</think>### 洛谷 AT_abc161_b 解题思路 题目通常要求从$N$个数值中筛选满足特定条件的元素,常见形式为**选择至少$M$个元素,且每个元素值需达到总和的$\frac{1}{4M}$以上**。具体步骤如下: 1. **计算总和**:遍历所有元素,累加得到总和$S$。 2. **确定阈值**:通过整数运算避免浮点误差,计算条件$a_i \times 4M \geq S$。 3. **统计满足条件的元素数量**:遍历数组,统计符合条件的元素个数$cnt$。 4. **输出结果**:若$cnt \geq M$,输出$M$;否则输出$cnt$。 ```cpp #include <iostream> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; vector<int> A(N); long long sum = 0; for (int i = 0; i < N; ++i) { cin >> A[i]; sum += A[i]; } int cnt = 0; for (int a : A) { if (a * 4 * M >= sum) { // 避免浮点运算 cnt++; } } cout << min(cnt, M) << endl; return 0; } ``` #### 关键点说明 - **整数运算优化**:通过比较$a_i \times 4M \geq S$代替$\frac{S}{4M}$,避免浮点精度问题[^1]。 - **边界条件**:总和可能为0或元素全为0,需确保逻辑正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值