DulcetAirman icon

Maximale Teilsumme

DulcetAirman | PRO | 06/11/12 12:49:30 PM UTC | 0 ⭐ | 564 👁️ | Never ⏰ | []
Java |

5.25 KB

|

None

|

0 👍

/

0 👎

package ch.fhnw.claudemartin.algd1.maxteilsumme;
 
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
 
public class MaxT {
 
  static int naive(byte[] a) {
    int sum = 0;
    int x;
 
    loop1: for (int left = 0; left < a.length; left++) {
      while (a[left] <= 0)
        continue loop1;
      loop2: for (int right = a.length - 1; right >= left; right--) {
        while (a[right] <= 0)
          continue loop2;
        x = 0;
        for (int i = left; i <= right; i++) {
          x += a[i];
        }
        if (x > sum)
          sum = x;
      }
    }
    return sum;
  }
 
  public static void main(String[] args) {
 
    test(new byte[] { 42 });// 42
    test(new byte[] { -1, 0, 1 });// 1
    test(new byte[] { 1, 0, 1 });// 2
    test(new byte[] { 1, 1, 1 });// 3
    test(new byte[] { -1 });// 0
    test(new byte[] { 10, 21, -13, 7, 9, -4, -9, 21, -6, 13, 17, 12, 1, -7, -6, 9 });// 79
    test(new byte[] { 31, -41, 59, 26, -53, 58, 97, -93, -23, 84 });// 187
 
    for (int i = 0; i < 10; i++) {
      test(1000 + i);
    }
 
    for (int i = 0; i < 10; i++) {
      test((int) Math.pow(10, i));
    }
  }
 
  static int seed = 0;
 
  private static void test(int n) {
    Random random = new Random(seed++);
    final byte[] a = new byte[n];
    for (int i = 0; i < a.length; i++) {
      a[i] = (byte) ((random.nextDouble() - 0.5) * Byte.MAX_VALUE);
    }
    test(a);
  }
 
  private static void test(final byte[] a) {
 
    // int[] a = { 2, -1, 3 };
    // System.out.println(Arrays.toString(a));
    long start = System.currentTimeMillis();
    final int maxT = maxTeilsumme(a);
    long end = System.currentTimeMillis();
    System.out.println("length: " + a.length);
    System.out.println("result: " + maxT);
    System.out.println("time (ms): " + (end - start));
 
    if (a.length <= 5000) {
      final long s = System.currentTimeMillis();
      int naive = naive(a);
      if (maxT != naive) {
        System.err.println("Wrong result!!!");
        System.err.println("Naive result: " + naive);
        System.err.println("Array: " + Arrays.toString(a));
      }
      System.out.println("time of naive impl. (ms): " + (System.currentTimeMillis() - s));
    }
    System.out.println("----------------");
  }
 
  static int maxTeilsumme(final byte[] a) {
    if (a.length == 0)
      return 0;
    final int left = 0;
    final int right = a.length - 1;
    // erst bei sehr grossen Arrays lohnt sich Multithreading:
    if (a.length < 1000000)
      return maxTeilsumme(a, left, right);
    // else:
 
    // System.out.println(left+", "+right);
    final int m = left + ((right - left) >> 1);
    assert m > left && m < right;
 
    final AtomicInteger vLsum = new AtomicInteger();
    Thread t1 = new Thread() {
      public void run() {
        vLsum.set(maxTeilsumme(a, left, m));
      };
    };
 
    final AtomicInteger vRsum = new AtomicInteger();
    Thread t2 = new Thread() {
      public void run() {
        vRsum.set(maxTeilsumme(a, m + 1, right));
      };
    };
 
    final AtomicInteger asum = new AtomicInteger();
    Thread t3 = new Thread() {
      public void run() {
        asum.set(sum(a, left, right));
      };
    };
 
    t1.start();
    t2.start();
    t3.start();
 
    try {
      t1.join();
      t2.join();
      t3.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
 
    return max(vLsum.get(), vRsum.get(), asum.get());
 
  }
 
  static int maxTeilsumme(final byte[] a, final int left, final int right) {
    assert right >= left;
    // System.out.println(left+", "+right);
    switch (right - left) {
    case 0:
      return a[left] > 0 ? a[left] : 0;
    case 1:
      return max(0, a[left], a[right], a[left] + a[right]);
    case 2:
      final int lft = a[left];
      final int mid = a[right - 1];
      final int rgt = a[right];
      return max(0, lft, mid, rgt, a[left] + mid, mid + a[right], a[left] + mid + a[right]);
    case 3:
      final int a1 = a[left];// right-3
      final int a2 = a[left + 1];// right-2
      final int a3 = a[right - 1];// left+2
      final int a4 = a[right];// left+3
      final int a12 = a1 + a2;
      final int a34 = a3 + a4;
      return max(0, a1, a2, a3, a4, a12, a2 + a3, a34, a12 + a3, a2 + a34, a12 + a34);
    default:
      int m = left + ((right - left) >> 1);
      assert m > left && m < right;
      int vLsum = maxTeilsumme(a, left, m);
      int vRsum = maxTeilsumme(a, m + 1, right);
      int asum = sum(a, left, right);
      return max(vLsum, vRsum, asum);
    }
  }
 
  static int sum(byte[] a, int left, int right) {
    int sum = 0;
    int rmax = 0;
    int m = left + ((right - left) >> 1);
    for (int i = m + 1; i <= right; i++) {
      sum += a[i];
      if (sum > rmax)
        rmax = sum;
    }
    sum = 0;
    int lmax = 0;
    for (int i = m; i >= left; i--) {
      sum += a[i];
      if (sum > lmax)
        lmax = sum;
    }
    return lmax + rmax;
  }
 
  static int max(int... vals) {
    assert vals.length > 0;
    int rv = Integer.MIN_VALUE;
    for (int i : vals) {
      if (i > rv)
        rv = i;
    }
    assert rv != Integer.MIN_VALUE;
    return rv;
  }
 
}

Comments