现在的位置: 首页 > 综合 > 正文

joj 2324 Go Dutch

2013年08月05日 ⁄ 综合 ⁄ 共 1622字 ⁄ 字号 评论关闭

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

3
10 93 73
12 69 40
88 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;
}

抱歉!评论已关闭.