问题 D: 筷子

题目描述

A先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A先生家里来了K个客人,A先生留下他们吃晚饭。加上A先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A先生只好清理了一下筷子,共N根,长度为T1,T2,T3,……,TN.现在他想用这些筷子组合成K+3双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A先生了,呵呵)

输入

共有两行,第一行为两个用空格隔开的整数,表示N,K(1≤N≤100, 0<K<50),第二行共有N个用空格隔开的整数,为Ti.每个整数为1~50之间的数。

输出

仅一行。如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。

样例输入

10 1

1 1 2 3 3 3 4 6 10 20

样例输出

5

 

思路:

这道题是一道动态规划题,首先我们要将所有筷子排序,

这样选定的筷子一定是相邻的,然后就需要用到dp的思想,

我们比较选第i个和第i-1个筷子与不选的区别得到状态转移方程:

b[i][j]=min(b[i-1][j],b[i-2][j-1]+f(a[i],a[i-1]))

代码:

#include<bits/stdc++.h>

using namespace std;

int f(int x,int y)//求一双筷子的长度差的平方

{

    int m=abs(x-y);

    return m*m;

}

int main()

{

    int n,k;

    cin>>n>>k;

    k=k+3;

    if(n<k*2)//当不能完成k双筷子时输出-1

    {

        cout<<-1;

        return 0;

    }

    int a[10001],b[202][202];

    for(int i=1;i<=n;i++)

    {

        cin>>a[i];

    }

    sort(a+1,a+1+n);//先将筷子排序

    for (int i=0;i<=n;i++)//初始化

    {

        b[i][0]=0;

        for(int j=1;j<=k;j++)

        b[i][j]=2e7;

    }

    for(int i=2;i<=n;i++)

        for(int j=1;j<=k;j++)

            b[i][j]=min(b[i-1][j],b[i-2][j-1]+f(a[i],a[i-1]));//状态转移方程

    cout<<b[n][k];

}

 

1.创建2个进程,使用消息队列方式实现进程间通信,通信内容为自己姓名和学号。 2.创建2个进程,使用共享内存方式实现进程间通信,通信内容为自己姓名和学号。 3.问题描述:五位哲学家围坐在一张圆形桌子上,桌子上有一盘饺子。每一位哲学家要么思考,要么等待,要么吃饺子。为了吃饺子,哲学家必须拿起两只筷子,但是每个哲学家旁边只有一只筷子,也就是筷子数量和哲学家数量相等,所以每只筷子必须由两个哲学家共享。设计一个算法以允许哲学家吃饭。算法必须保证互斥(没有两位哲学家同时使用同一只筷子),同时还要避免死锁(每人拿着一只筷子不放,导致谁也吃不了)。 实验内容:以哲学家进餐模型为依据,在 Linux 控制台环境下创立 5 个进程,用 semget 函数创立一个信号量集〔5 个信号量,初值为 1〕,模拟哲学家的思考和进餐行为:每一位哲学家饥饿时,先拿起左手筷子,再拿起右手筷子筷子是临界资源,为每一支筷子定义 1 个互斥信号量;拿到筷子需要先对信号量做 P 操作,使用完释放筷子对信号量做 V 操作。 伪代码描述: semaphore chopstick[5]={1,1,1,1,1}; 第 i 位哲学家的活动可描述为: do{ printf("Philopher %d is thinking\n",i); printf("Philopher %d is hungry\n",i); P(chopstick[i]); //拿左筷子 P(chopstick[(i+1) % 5]); //拿右筷子 printf("Philopher %d is eating\n",i); V(chopstick[i]); //放左筷子 V(chopstick[(i+1) % 5]); //放右筷子 … }while[true]; 请根据伪代码编写程序 philosopher1.c,创建该组进程并运行,观察进程是否能一直运行下去。假设停滞那么发生了什么现象?请分析原因,并给出解决方法,编写程序 philosopher2.c 进行验证。
12-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值