BSOJ:3362 聪明的农民 贪心

29 篇文章 0 订阅
11 篇文章 0 订阅
3362 -- 【模拟试题】聪明的农民
Description
在城中有一个贪婪而愚蠢的领主,他总是不管农民的死活,疯狂地敲诈农民们辛勤耕种的劳动成果。眼看每年的秋收日十月十日已经到了,这时城中所有的农民在忙完一年的收成后,又要向领主上缴一年的粮食了。很久以来当地就采用一个特殊的“抽签”决定各户农民上缴粮食的方法:领主将一些写有不同的数的纸条放入一个盒子中,每户农民从中抽取两张纸条并在第二天上缴和两张纸条上的数值相乘结果同样数量的粮食。
城中的农民是个既聪明又团结的整体,他们非常痛恨残暴的领主,不希望向他多交一粒粮食,所以他们每年在抽完签后,秘密地交换一些纸条,使最后向领主上缴的粮食总量最少。不幸的是,以往决定如何交换纸条的老农夫杰克病倒了,不能为大家出力了,所以请你帮助他们决定如何交换纸条。另外,为了瞒过领主,活动只能在夜间悄悄进行,因此务必要使交换次数最少(两个农民将各自的一张纸条对调叫做一次交换)。

Input
文件的第一行为农户数目n(n≤500),接下来的n行,每行为两个数a、b,其中a、b两数均不超过1000。相邻两个数之间由一个或多个空格分隔。

Output
输出文件由两个数组成,每个数占一行,分别为交换后向领主上缴的粮食总量和需要交换的总次数。

Sample Input
3
10 13
7 12
9 6

Sample Output
252
1

第一个问是一个比较数学的问题,可以证明,大*小得到的乘积最小,这里我们肯定先贪心优化比较大的数,于是排序,两根指针,头*尾累加即可。
第二个问题可以根据第一个问的结果进行求解,进行每组枚举,如果“原本组”与“匹配组”的不同,就修改各自组别,sum++,输出即可。
yo,这里是代码。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int n,ans1=0,ans2=0,a[1000005]={0};
int b[100005]={0};
int idx[100045]={0};
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int k,q;
        scanf("%d%d",&k,&q);
        a[i*2-1]=k;a[i*2]=q;
        b[i*2-1]=k;b[i*2]=q;
        idx[k]=idx[q]=i;
        }
        sort(a+1,a+2*n+1);
        for(int i=1;i<=n;i++)ans1+=a[i]*a[2*n-i+1];//贪心
        printf("%d\n",ans1);
        for(int i=1;i<=n;i++)
        {
                if(idx[a[i]]!=idx[a[2*n-i+1]])
                {
                        ans2++;
                        bool fl=0;
                        for(int j=1;j<=n;j++)
                        {
                                if(idx[b[j*2-1]]==idx[a[i]]&&(b[j*2-1]!=a[i]))
                                {
                                        idx[b[2*j-1]]=idx[a[2*n-i+1]];
                                        idx[a[2*n-i+1]]=idx[a[i]];
                                        fl=1;
                                        break;
                                }
                        }
                        if(fl)continue;
                        for(int j=1;j<=n;j++)
                        {
                                if(idx[b[2*j]]==idx[a[i]]&&(b[2*j]!=a[i]))
                                {
                                        idx[b[2*j]]=idx[a[2*n-i+1]];
                                        idx[a[2*n-i+1]]=idx[a[i]];
                                        break;
                                }
                        }//交换各自组别
                }
        }
        printf("%d\n",ans2);
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值