【算法】接水问题-自己的思考和解决过程。

最近,喜欢在oj上刷算法了。。还是新手,希望有人来一起交流交流。。

贴上接水问题的描述:

  学校里有一个水房,水房里一共装有m 个龙头可供同学们打开水,每个龙头每秒钟的 供水量相等,均为1。 现在有n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从1 到n 编号,i 号同学的接水量为wi。接水开始时,1 到m 号同学各占一个水龙头,并同时打 开水龙头接水。当其中某名同学j 完成其接水量要求wj 后,下一名排队等候接水的同学k 马上接替j 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即 j 同学第x 秒结束时完成接水,则k 同学第x+1 秒立刻开始接水。若当前接水人数n’不足m, 则只有n’个龙头供水,其它m−n’个龙头关闭。 现在给出n 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

输入描述:

  第1 行2 个整数n 和m,用一个空格隔开,分别表示接水人数和龙头个数。 第2 行n 个整数w1、w2、……、wn,每两个整数之间用一个空格隔开,wi 表示i 号同学的接水量。

输入样例:

5 3

4 4 1 2 1

输出描述:

  输出只有一行,1 个整数,表示接水所需的总时间。

输出样例:

4

HINT:时间限制:1.0s 内存限制:64.0MB

开始!

       我最初的想法是构造水龙头和人的数据结构,并且这两个数据结构彼此互相联。。然后开始遍历水龙头是否有人在接水,有则将该人的对象保存到当前水龙头,直到接完。很明显,这个思路是可行的哈哈,不过AC不了啊。。想了一晚也没能成功优化。

 

然后第二天在上小程序课的时候我又开始想别的方法进行解决(上课不认真?小程序自学过哈哈,主要听老师讲我没注意的地方)。不久我就想出一个新的思路!

 

就根据输入案例进行分析:

5 3

4 4 1 2 1

第一行:5 是接水人数,3是水龙头数

第二行:5个数分别是5个人的接水量

题目中有个重要的点,就是接水顺序是按编号来的:

        就拿上面例子,第一次接水就是1号2号3号,4号5号等待。当第一次接水完成后,这时1号2号3号剩余的接水量为3 3 0。好,3号同学已经接水完成,所以3号水龙头就换4号同学上去接水,而不能是换5号上去。

下面继续我的分析。

设接水人数为n,水龙头数为m

将接水量放到数组则有 {4, 4, 1, 2, 1},计算总接水量得 12。

我们关注数组的前m位(水龙头数,这里例子为3):{4, 4, 1, 2, 1}

这时数组就逻辑上就分成了两部分,第一部分[0:m-1],第二部分[m:n-1]。第一部分是正在接水的,完成一次接水则里面的元素值减掉1,当第一部分有元素变为0时则表示对应的人已经接完水,可以在数组的第二部分找到不为0的元素与之交换。在这里,有题目中第二个要重要的点,就是当一个人接完水后,后面的人会立马接上,也就是上面交换操作要在接完水的同时刻内完成。【【有点难表述Σ(っ °Д °;)っ】】

下面推演下过程应该就懂了: 

原始:{4, 4, 1, 2, 1}

设时间为 time = 0;未接水人数为 count = 5

while (count>n){

第一次>>接水前:{4, 4, 1, 2, 1} >> 接水后:{3, 3, 0, 2, 1} >> 发现第三个人接水完成,故开始向数组的第二部份遍历不为0的元素进行交换 swap(2,3);count--(count=4)>>{3, 3, 2, 0, 1} >> 完成本次接水 time++(time= 1)

第二次>>接水前:{3, 3, 2, 0, 1} >> 接水后:{2, 2, 1, 0, 1} >> 没有人接水完成,故继续 >>完成本次接水 time++(time= 2)

第三次>>接水前:{2, 2, 1, 0, 1} >> 接水后:{1, 1, 0, 0, 1} >> 发现第三个人接水完成,故开始向数组的第二部份遍历不为0的元素进行交换 swap(2,3);count--(count=3) >> {1, 1, 1, 0, 0} >> 完成本次接水 time++(time= 3)

第三次>>接水前:{1, 1, 1, 0, 0} >> 接水后:{0, 0, 0, 0, 0} >> 所有人已经完成接水>>count-=3(count=0) >> 完成本次接水 time++(time= 4)

}

输出 4。

下面上代码:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] powers = new int[n+1];//接水量数组【懵逼了,写了从1开始,无所谓了。。】
        int i = 1;
        while(i<=n && sc.hasNext()){
            powers[i] = sc.nextInt();
            i++;
        }
        int count = n; //接水人数
        int cur = m;//用来存遍历数组第二部分停下的位置。
        int time = 0;//总的接水时间时间
        while(count>0){
            for(int k = 1;k<=m;k++){
                if(powers[k]>0){//接水量大于0
                    if(powers[k]-1==0){//接水量即将为0时 处理接水完成和下一个人的无缝接上操作
                        powers[k]--;
                        count--;
                        //cur
                        for (int j = cur + 1; j < powers.length; j++) {
                            if (powers[j] > 0) {
                                int temp = powers[k];
                                powers[k] = powers[j];
                                powers[j] = temp;
                                cur = j;
                                break;
                            }
                        }
                        continue;
                    }
                    powers[k]--;
                }else if(powers[k] == 0){
                    for(int j = cur + 1;j<powers.length;j++){
                        if(powers[j] > 0){
                            int temp = powers[k];
                            powers[k] = powers[j];
                            powers[j] = temp;
                            cur = j;
                            break;
                        }
                    }
                }
            }
            time += 1;
        }
        System.out.println(time);
    }
}

 

代码有些冗余哈,希望有大神来指导一下~

A掉了哈哈。。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值