- 论坛徽章:
- 1
|
本帖最后由 vbs100 于 2014-06-01 11:26 编辑
感觉这个应该是对的了,大致思路是这样的:
1. 用一个N*N数组C,保存A B数组任的意两个数字的数字差和这两个数在A B数组中对应的下标,并按数字差的大小排序
2. 根据当前A B两个数组的和差,在C中找到一个数字差区间[2*Xi,2*Xj],使得和差正好落在这个区间上,计算两个端点代表的交换在交换后的和差,在这三个和差中取绝对值最小的
3. 交换选中的A B数组中两个选定的数,更新数组和差、更新数组C,重复过程2直到结束
终止条件:
1. 当前和差为0
2. 当前和差比两个新计算出来的和差都小
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #define N 10
- struct delta
- {
- int i;
- int j;
- int d;
- };
- int a[N];
- int b[N];
- struct delta c[N][N];
- int compar(const void *a1, const void *a2)
- {
- return ((struct delta*)a1)->d - ((struct delta*)a2)->d;
- }
- void swap(int *a, int *b)
- {
- int tmp;
- tmp = *a;
- *a = *b;
- *b = tmp;
- }
- void update(int i, int j)
- {
- struct delta *p;
- for(p = &c[0][0]; p <= &c[N-1][N-1]; p++)
- {
- if(p->i == i)
- p->d = a[i]-b[p->j];
- if(p->j == j)
- p->d = a[p->i]-b[j];
- }
- qsort(&c, N * N, sizeof(struct delta), &compar);
- }
- int sum(int array[])
- {
- int i, sum=0;
- for(i = 0; i < N; i++)
- sum += array[i];
- return sum;
- }
- void print(int array[])
- {
- int i;
- for(i = 0; i < N; i++)
- printf("%d ", array[i]);
- printf("\n");
- }
- void findsection(int dsum, struct delta **d1, struct delta **d2)
- {
- struct delta *p, *q;
- if(dsum <= c[0][0].d * 2)
- {
- *d1 = NULL;
- *d2 = &c[0][0];
- return;
- }
- if(dsum >= c[N-1][N-1].d * 2)
- {
- *d1 = &c[N-1][N-1];
- *d2 = NULL;
- return;
- }
- for(p = &c[0][0], q = p + 1; q <= &c[N-1][N-1]; p++, q++)
- {
- if(dsum >= p->d * 2 && dsum <= q->d * 2)
- {
- *d1 = p;
- *d2 = q;
- break;
- }
- }
- }
- int main()
- {
- int i,j,k;
- int sum_a,sum_b,sum_ab;
- srand(time(NULL));
- for(i = 0; i < N; i++)
- {
- a[i] = rand()%100;
- b[i] = rand()%100;
- }
- for(i = 0; i < N; i++)
- for(j = 0; j < N; j++)
- {
- c[i][j].i = i;
- c[i][j].j = j;
- c[i][j].d = a[i]-b[j];
- }
- qsort(&c, N * N, sizeof(struct delta), &compar);
- while(1)
- {
- struct delta *p1 ,*p2;
- sum_a = sum(a);
- sum_b = sum(b);
- sum_ab = sum_a - sum_b;
- print(a);
- print(b);
- printf("sum(a)=%d sum(b)=%d sum(a)-sum(b)=%d\n", sum_a, sum_b, sum_ab);
- if(sum_ab == 0)
- break;
- findsection(sum_ab, &p1, &p2);
- if(p1 == NULL)
- {
- i = p2->i;
- j = p2->j;
- swap(&a[i], &b[j]);
- update(i, j);
- }
- else if(p2 == NULL)
- {
- i = p1->i;
- j = p1->j;
- swap(&a[i], &b[j]);
- update(i, j);
- }
- else
- {
- if(abs(sum_ab - p1->d*2) <= abs(sum_ab - p2->d*2))
- {
- if(abs(sum_ab)<=abs(sum_ab - p1->d*2))
- break;
- swap(&a[p1->i], &b[p1->j]);
- update(p1->i, p1->j);
- }
- else
- {
- if(abs(sum_ab)<=abs(sum_ab - p2->d*2))
- break;
- swap(&a[p2->i], &b[p2->j]);
- update(p2->i, p2->j);
- }
- }
- }
- return 0;
- }
复制代码 下面是n=10,随机生成a b数组的计算结果,基本上都是5次之内就可以完成交换,收敛的速度还是非常快的
vbs100@ubuntu:~$ ./a.out
41 83 53 2 46 31 11 91 44 16
69 40 84 17 99 58 49 34 93 83
sum(a)=418 sum(b)=626 sum(a)-sum(b)=-208
41 83 53 99 46 31 11 91 44 16
69 40 84 17 2 58 49 34 93 83
sum(a)=515 sum(b)=529 sum(a)-sum(b)=-14
49 83 53 99 46 31 11 91 44 16
69 40 84 17 2 58 41 34 93 83
sum(a)=523 sum(b)=521 sum(a)-sum(b)=2
vbs100@ubuntu:~$
vbs100@ubuntu:~$ ./a.out
12 32 15 60 25 41 96 30 0 57
8 98 72 76 11 85 48 33 78 91
sum(a)=368 sum(b)=600 sum(a)-sum(b)=-232
12 32 15 60 25 41 96 30 98 57
8 0 72 76 11 85 48 33 78 91
sum(a)=466 sum(b)=502 sum(a)-sum(b)=-36
12 32 33 60 25 41 96 30 98 57
8 0 72 76 11 85 48 15 78 91
sum(a)=484 sum(b)=484 sum(a)-sum(b)=0
vbs100@ubuntu:~$
vbs100@ubuntu:~$ ./a.out
14 64 88 21 71 42 70 50 18 38
83 38 29 52 72 30 5 83 63 23
sum(a)=476 sum(b)=478 sum(a)-sum(b)=-2
14 64 88 21 72 42 70 50 18 38
83 38 29 52 71 30 5 83 63 23
sum(a)=477 sum(b)=477 sum(a)-sum(b)=0
vbs100@ubuntu:~$
vbs100@ubuntu:~$ ./a.out
68 99 28 87 66 45 8 18 55 78
62 67 46 90 74 44 9 15 77 51
sum(a)=552 sum(b)=535 sum(a)-sum(b)=17
68 90 28 87 66 45 8 18 55 78
62 67 46 99 74 44 9 15 77 51
sum(a)=543 sum(b)=544 sum(a)-sum(b)=-1
|
|