There are N person and N job to do. The i-th person do j-th job will cost different certain money. Choose a scheme that every person only do one different job, and total
cost is minimum.
Input
Input consists of several test cases. The first line of each case is a positive interger N(2<=N<14), it is the number of persons (and jobs). The next N line include N integers,
the cost of i-th person doing j-th job is the j-th element in line i.
Output
For each input N, you should the minimum cost in one line.
Sample Input
310 93 7312 69 4088 62 76
Sample Output
112
狀態壓縮DP。因為N比較小,所以容易想到狀態壓縮DP。
用2進位來表示工作的分配狀態,以N=5為例
比如01011,表示1-5份工作,未分配,分配,未分配,分配,分配
如果在01011的狀態基礎上給第4個人分配工作,那麼新的狀態可以有11011、01111,要更新這幾個狀態的解。
反過來想,如何求狀態01111的最優解,那麼只需從子問題中的最優解中求即可,不需要關心子問題的最優解是如何達到的。
如01111狀態相關的狀態(子問題)有:
01110(在2,3,4個工作已指派的情況下,第4個人選第5份工作,即可達到狀態01111)
01101(在2,3,5個工作已指派的情況下,第4個人選第4份工作,即可達到狀態01111)
01011(在2,4,5個工作已指派的情況下,第4個人選第3份工作,即可達到狀態01111)
00111(在3,4,5個工作已指派的情況下,第4個人選第2份工作,即可達到狀態01111)
#include<stdio.h>#include<memory.h>#include<limits.h>int m[14][1<<14];//m[i][j]表示在前i個人已指派工作,工作分配狀態是j的二進位表示的最優解bool flag[14][1<<14];//flag[i][j]標記狀態是否可達或合法int a[14][14];//儲存輸入int main(){int n, i, j, k; while(scanf("%d",&n) != EOF) { memset(flag, false, sizeof(flag)); int max = 1<<n;//最大的狀態是max-1,即n位全為1,用max表示狀態上限 for(i = 1; i <= n; i++) for(j = 1;j <= n; j++) scanf("%d", &a[i][j]); for(i = 1; i <= n; i++) for(j = 0; j< max; j++) m[i][j] = INT_MAX; m[0][0] = 0; flag[0][0] = true; for(i = 1; i <= n; i++) for(j = 0;j < max; j++)//對前i-1個人已指派工作的所有可達狀態處理 { if(!flag[i-1][j]) continue;//如果(i-1,j)不是有效狀態跳過 for(k = 1;k <= n; k++)//對第i個人分配可以分配的工作 { int mask = 1<<(k-1); if(j&mask) continue;//第k個工作已指派,跳過 if(m[i-1][j]+a[i][k] < m[i][j|mask])//將第k個工作分配給第i個人,同時更新所達到狀態的解 { m[i][j|mask] = m[i-1][j]+a[i][k]; flag[i][j|mask] = true; } } } printf("%d\n", m[n][(1<<n)-1]); } return 0;}