joj 2324 Go Dutch

来源:互联网 发布:台湾民众心态知乎 编辑:程序博客网 时间:2024/06/15 05:25
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;}