mask

小說:二月蘭種子要浸水嗎?作者:扁戲密開更新時間:2019-05-22字數:67970

崔乾佑輕輕嘆了。氣,他立刻下令道:“全軍出動,去救援沙陀軍!”

繡球花播種量一畝多少斤?

就像過去剛剛掌握一階基因鎖的時候他也相信自己能踏入五階基因鎖成為圣人時候一樣。
唐王仍認得他,道:“你是前日送袈裟的和尚?”菩薩道:“正是?!碧仆醯溃骸澳慵葋泶颂幝犞v,只該吃些齋便了,為何與我法師亂講,擾亂經堂,誤我佛事?”

“老先生也不簡單,有機會的話比賽見吧?!眲﹥扇藢Ψ降脑囂蕉际寝D瞬即逝,因此旁人難以察覺,只不過剛才的試探均是讓雙方對對方有了一個評價。

mask


TSP問題描述:

  旅行商問題,即TSP問題(Travelling Salesman Problem)又譯為旅行推銷員問題、貨郎擔問題,是數學領域中著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最后要回到原來出發的城市。路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值。這篇文章解決的tsp問題的輸入描述是:

TSP問題的動態規劃解法:

  引用一下這篇文章,覺得作者把動態規劃算法講的非常明白:https://blog.csdn.net/derek_tian/article/details/45057443

動態規劃算法的并行:

  終于到了文章的重點,如何高效率的將主問題拆開并分配給各個線程運算是值得研究的話題。這里先引用動態規劃算法的示意圖:

(圖2)

  圖中所示的是城市數為4的問題,從第一行到第二行,把問題拆分成了三個子問題,這三個子問題互不影響互不相關。將這三個子問題再一次拆分,每個問題又能拆出兩個問題。將這個規律推廣到n,城市數為n的問題通過第一次拆分可以變為n-1個子問題,再拆分一次共可以變為(n-1)*(n-2)個子問題。

  有了能把問題拆成互不相干的子問題作為前提,在并行時就并不需為數據頻繁的加鎖解鎖,能比較順利地完成并行的操作了。接下來是具體的實現手段:

  首先在全局維護唯一一個二維表,所有子線程的讀取與修改都是在這一張表上進行的。例程中就是dp變量。

  接下來定義一個函數,用來求解每個子問題,這個時候出現了另一個問題:怎么樣表示一個子問題。在動態規劃算法中有一個狀態壓縮的概念,即為用一段二進制碼表示城市的集合,例如共五個城市時表示{1, 3, 4}這個集合即為二進制"11010"。相同的思路,對于d(1,{2,3})問題,我們給函數輸入起點,以及目標的集合,完整的表示問題。函數內選擇的是遞歸算法,因為非遞歸算法很難保證子問題互不相關(可能也只是我懶得想,有思路的同學可以在評論區中討論一下)。具體的動態規劃遞歸實現算法很多文章中都有,我就不過多贅述了。下面是這一部分的源代碼:

  *注意:我在寫這個函數的時候規定的setMask是包含了起點城市的,也就是對于d(1,{2,3})這個問題傳入函數的參數的是(1,0b"1110")。

int TSP( int x, int setMask ) {
    int mask, i, minimum;
    if ( dp[ setMask ][ x ] != -1 )
        return dp[ setMask ][ x ]; /* if already have value */
    mask = 1 << x;
    dp[ setMask ][ x ] = 1e9; /* set infinite */
    for ( i = 0; i < n; ++i ) {
        if ( i != x && ( setMask & ( 1 << i ) ) && map[ i ][ x ] != 0 ) { /* if have path */
            minimum = TSP( i, setMask - mask ) + map[ i ][ x ] ;
            dp[ setMask ][ x ] = min( dp[ setMask ][ x ], minimum);
        }
    }
    return dp[ setMask ][ x ];
}

  現在我們有了表達子問題的方法,就該開始解決具體怎么拆開問題的算法了。問題的要求中說明了最大可以創建的線程數,也就是說為了保證盡可能高的效率,程序中應該將問題拆到數量剛好大過線程數的情況。

  當我們計算出了應該拆分的層數后,就該為產生的一大波子問題生成描述了。

  有了之前定義子問題動態規劃的算法為基礎,其實可以發現,對于同一個setMask,其產生的同輩問題數是很容易得出來的。就拿剛剛的例子d(1,{2,3})來說,它的setMask是"1110",起點是1號城市。然而,對于與這個問題互為同輩關系的d(2,{1,3}),d(3,{1,3})問題來說,他們的setMask也都是"1110",只不過起點依次是2和3號城市。所以只要生成出了這個集合,其對應的問題都能很容易表示,這也就把工作的重心轉義到了如何生成這個集合,也就是例程中是setMask。

  對于從同一個整道題求解的問題分離出來的子問題來說,其城市集合其實是一個組合數。我們還選取圖2作為例子,現在經過計算后,我們需要把主問題拆分兩層,即拆到d(2,{3})這一層。我們列出所有的集合,分別是"1100", "1010", "1010",發現了嗎,其實這些集合也就是剔除了起點城市以后,將兩個1與一個0進行組合的所有情況。這個規律同樣可以推廣到n個城市,如果要將問題拆分k層,所有的問題集合即是n-k-1個1與k個0的所有組合數。

  希望我講清楚了里面的數學關系,如果覺得我講的有問題或者看不懂的同學可以在評論區留言……以下是上述數學過程的c語言代碼,為了邏輯更清晰我將計算組合數和求解所有組合數封成了factorial和setCombination函數:

    while (t > nn) { /* let all thread have work to do */
        nn *= (nn - 1);
        nc += 1; /* extends layers until t > nn */
    }
    j = 0;
    candiNum = malloc(sizeof(int) * (n - 1));
    for (i = 0; i < n; ++i) { /* candiNum set means all cities exclude the start piont*/
        if (i != s) {
            candiNum[j] = i; /* exclude the start point */
            j++;
        }
    }
    combNum = factorial(nc, n - 1); /* calculate combination number */
    combSet = malloc(sizeof(int) * combNum);
    combptr = combSet;
    numOf1 = n - 1 - nc; /* there should have `numOf1` of 1 in every item */
    setCombination(candiNum, n - 1, numOf1);
    posOf1 = malloc(sizeof(int) * numOf1); /* arr to store the position of 1 in each comb */

  接下來就是使用pthread創建線程來求解每一個子問題了。其中主函數作為調度線程來給0~t-1個線程依次分配任務。因為基本上可以認為每一個平行的子問題計算的時間是完全一樣的,所以只需要先給0~t-1個線程分配0~t-1號任務,再等待到0號線程結束以后,為其分配t號任務,以此類推。當所有的子問題都被解決以后,dp這個二維表中已經有所有我們需要的子問題結論了。此時主問題的答案可以很快通過這些答案計算出來,也沒有并行的必要了。最后提供整個程序的代碼以及Makefile:

?

// file tsp.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include "tsp.h" #include <time.h> #define min(a,b) (((a)<(b))?(a):(b)) /* macro func of min */ time_t tm; int ** map, ** dp, * combSet, * combptr, * posOf1, n; /* init vars */ trdArgs args[20]; pthread_t tid[20]; /* thread ids */ int TSP( int x, int setMask ) { int mask, i, minimum; if ( dp[ setMask ][ x ] != -1 ) return dp[ setMask ][ x ]; /* if already have value */ mask = 1 << x; dp[ setMask ][ x ] = 1e9; /* set infinite */ for ( i = 0; i < n; ++i ) { if ( i != x && ( setMask & ( 1 << i ) ) && map[ i ][ x ] != 0 ) { /* if have path */ minimum = TSP( i, setMask - mask ) + map[ i ][ x ] ; dp[ setMask ][ x ] = min( dp[ setMask ][ x ], minimum); } } return dp[ setMask ][ x ]; } void * trd(void * SArg) { TSP((*(trdArgs *)SArg).startPoint, (*(trdArgs *)SArg).setMask); return NULL; } void setCombination(int arr[], int n, int r) { /* set all combination into combptr */ int * data = malloc(sizeof(int) * r); /* Temporary array to store current combination */ combinationUtil(arr, data, 0, n - 1, 0, r); free(data); /* avoid leak */ } void combinationUtil(int arr[], int data[], int start, int end, int index, int r) { int i, j, tmpi = 0; /* init vars */ if (index == r) { for (j = 0; j < r; j++) /* add nums to binay */ tmpi |= (1 << data[j]); *combptr = tmpi; combptr++; /* next cell in array */ return; } for (i = start; i <= end && end - i + 1 >= r - index; i++) { /* recersive */ data[index] = arr[i]; combinationUtil(arr, data, i + 1, end, index + 1, r); /* call selfe */ } } long factorial(int m, int n) { /* caculate combination number */ int i, j; long ans = 1; if (m < n - m) m = n - m; /* C(m,n)=C(n-m,n) */ for (i = m + 1; i <= n; i++) ans *= i; for (j = 1; j <= n - m; j++) ans /= j; return ans; /* answer */ } int main() { long combNum; int t, s, i, j, k, nn, nc, ans, numOf1, * candiNum, * combSet, * tmptr; /* init vars */ nc = 0; scanf("%d %d %d", &t, &n, &s); /* get &t, &n, &s */ if (t < 0 || n <= 0 || n <= s || s < 0) {printf("-1 "); return 0;} /* error input */ if (n == 1) {printf("0 "); return 0;} nn = n - 1; /* first layer */ map = malloc(sizeof(int *)*n); /* alloc for 2dim array: map */ tmptr = malloc(sizeof(int) * n * n); for (i = 0; i < n; ++i) { map[i] = tmptr; /* set 2dim to 1dim */ tmptr += n; } dp = malloc(sizeof(int *) * (1 << n)); /* alloc for 2dim array: map */ tmptr = malloc(sizeof(int) * (1 << n) * n); for (i = 0; i < (1 << n); ++i) { dp[i] = tmptr; /* set 2dim to 1dim */ tmptr += n; } for (i = 0; i < n; i++) /* get the map */ for (j = 0; j < n; j++) scanf("%d", &map[i][j]); /* store */ memset(dp[0], -1, sizeof(int) * (1 << n) * n); /* fill all dp with -1 */ for ( i = 0; i < n; ++i ) dp[ 1 << i ][ i ] = map[ 0 ][ i ]; while (t > nn) { /* let all thread have work to do */ nn *= (nn - 1); nc += 1; /* extends layers until t > nn */ } j = 0; candiNum = malloc(sizeof(int) * (n - 1)); for (i = 0; i < n; ++i) { /* candiNum set means all cities exclude the start piont*/ if (i != s) { candiNum[j] = i; /* exclude the start point */ j++; } } combNum = factorial(nc, n - 1); /* calculate combination number */ combSet = malloc(sizeof(int) * combNum); combptr = combSet; numOf1 = n - 1 - nc; /* there should have `numOf1` of 1 in every item */ setCombination(candiNum, n - 1, numOf1); posOf1 = malloc(sizeof(int) * numOf1); /* arr to store the position of 1 in each comb */ k = 0; for (i = 0; i < combNum; ++i) { tmptr = posOf1; for (j = 0; j < n; ++j) { /* go through all bits */ if ((combSet[i] & (1 << j)) != 0) { *tmptr = j; tmptr++; /* point to next cell */ } } for (j = 0; j < numOf1; ++j) { /* arrange jobs */ args[k].id = k; /* set thread id arg */ args[k].startPoint = posOf1[j]; args[k].setMask = combSet[i]; /* set thread set mask args */ pthread_join(tid[k], NULL); pthread_create(&tid[k], NULL, trd, &args[k]); /* new thread */ k = (k + 1) % t; } } for (i = 0; i < t; ++i)/* join all thread */ pthread_join(tid[i], NULL); ans = TSP(0, ( 1 << n ) - 1); if (ans == 1e9) printf("-1 "); else printf("%d ", ans); /* final answer */ free(dp[0]); /* free */ free(dp); free(map[0]); /* free */ free(map); free(posOf1); /* free */ free(combSet); free(candiNum); /* free */ return 0; }

?

// file tsp.h

typedef struct threadArgs {
    int id;
    int startPoint;
    int setMask;
} trdArgs;

int TSP( int x, int setMask );

void * trd(void * SArg) ;

void combinationUtil(int arr[], int data[], int start, int end,
                     int index, int r);

void setCombination(int arr[], int n, int r) ;

long factorial(int m, int n) ;

?

Makefile:

CC=gcc
CFLAGS=-Wpedantic -Wall -Wextra -Werror -std=c89 -pthread -D_GNU_SOURCE

tsp.o: tsp.c tsp.h
    ${CC} ${CFLAGS} tsp_blog.c -o tsp.o

?

歡迎沒有完全看懂的讀者隨時提問,文中的例程也不一定是最好的算法,還請有想法的讀者能不吝賜教。

當前文章:http://www.hfcxdn.com/kan/c3c8dhqz3k.html

發布時間:2019-05-22 04:10:45

龜甲冬青花期是幾月? 南方紫藤冬天落葉嗎? 紫藤花什么時候開花呢? 金邊闊葉麥冬多少錢一株? 草地早熟禾種子的形狀和外觀_圖片 番石榴種子幾月播種最好? 紫花苜蓿籽多少錢一斤? 將軍菊苣牧草種子一公斤多少錢?

火棘價錢貴嗎? 美國大花凌霄小苗什么價格? 猛一看是木瓜,近看才知道是貼梗海棠 四川適合種植多年生黑麥草嗎? 矮桿百日草可以移栽嗎? 剪秋羅多少天出苗? 哪里有草坪草種出售? 10月可以播種山櫻桃嗎? 華山松種子價格哪里最低?

編輯:辛北宗成

我要說兩句: (0人參與)

發布
捕鱼达人之深海狩猎