练习题 Dan’s Work Distribution
完整题目描述:
Electronics Company owned by Dan has N employees.
This year, the company has N new projects to work on.
Each employee should be assigned to only one task.
In other words, multiple employees can’t work on the same task.
Suppose the employees and tasks are numbered from 1 to N.
The success probability is Pi,j if the ith employee completes the jth task.
Dan wants to assign each employee to each task in order to maximize the success probability of the projects.
Let’s write a program to calculate the max success probability.
[Input]
The first line contains T, the number of test cases.
For each test case, the first line has an integer N(1 ≤ N ≤ 16).
The ith line of the subsequent N lines has space-separated N integers Pi,1, … , Pi,N(0≤Pi,j≤100).
Pi,j denotes the success probability of the ith employee completing the jth task in percentage.
[Output]
For each test case, print space-separated “#T” and the max success probability of all projects.
Print the probability in percentage rounded to 6 decimal places from the 7th decimal place.
Input Example
1 // Number of test cases 3 // N employees of the 1st TC 13 0 50 // Success probability, P1,j, of the 1st employee 12 70 90 // Success probability, P2,j, of the 2nd employee 25 60 100 // Success probability, P3,j, of the 3rd employee
Output Example
#1 9.100000
sample_input 下载链接:https://files.cnblogs.com/files/proscientist/work_distrib_input.zip
题解:状态压缩 + DFS
1 /* MH58 Dan’s Work Distribution 2 题意:有最多16个员工,最多16个项目,每个员工做且仅做一个项目,成功率各不相同 3 求如何分配使所有项目都完成的成功率之积最大 4 */ 5 #include<stdio.h> 6 #define SIZE 16 7 double inData[SIZE][SIZE]; 8 double DP[SIZE][(1 << SIZE)]; 9 int nWorkers; 10 11 //pattern表示当前worker可选的项目,1表示当前worker可选 12 double getMaxProb(int worker, int pattern){ 13 if (worker == nWorkers) return 1.00; 14 if (DP[worker][pattern] >= 0) return DP[worker][pattern]; 15 double maxProb = 0; 16 for (int i = 0; i < nWorkers; i++){ 17 if (pattern & (1 << i)){ 18 maxProb = max(maxProb, 19 inData[worker][i] * getMaxProb(worker + 1, pattern - (1 << i))); 20 } 21 } 22 DP[worker][pattern] = maxProb; 23 //dfs记忆化搜索,记录当前员工及以后的所有员工完成这个pattern的任务,最大的收益积 24 return maxProb; 25 } 26 27 int main(int argc, char** argv){ 28 scanf("%d", &TC); 29 for (int test_case = 1; test_case <= TC; ++test_case){ 30 scanf("%d", &nWorkers); 31 for (int i = 0; i < nWorkers; i++){ 32 for (int j = 0; j < nWorkers; j++){ 33 scanf("%lf", &inData[i][j]); 34 inData[i][j] /= 100; 35 } 36 } 37 int maxVal = (1 << nWorkers); 38 for (int i = 0; i < nWorkers; i++){ 39 for (int j = 0; j < maxVal; j++) { 40 DP[i][j] = -1; 41 } 42 } 43 double result = 0; 44 result = getMaxProb(0, maxVal - 1); 45 printf("#%d %lf\n", test_case, result * 100); 46 } 47 return 0; 48 }
或 非递归写法:
1 #include <stdio.h> 2 #define MAX 65540 3 #define max(a,b) ((a)>(b)?(a):(b)) 4 double dp[MAX]; 5 int num[MAX]; 6 double data[20][20]; 7 int main(void){ 8 freopen("sample_input.txt", "r", stdin); 9 setbuf(stdout, NULL); 10 for (int i = 0; i < (1 << 16); ++i) 11 num[i] = 0; 12 //num表示数字i表示成二进制有多少个1 13 for (int i = 0; i < (1 << 16); ++i) 14 for (int j = 0; j < 16; ++j) 15 if (i&(1 << j)) 16 ++num[i]; 17 18 int T, N; 19 scanf("%d", &T); 20 for (int tc = 1; tc <= T; ++tc){ 21 scanf("%d", &N); 22 for (int i = 0; i < N; ++i) 23 for (int j = 0; j < N; ++j){ 24 scanf("%lf", &data[i][j]); 25 data[i][j] /= 100.0; 26 } 27 28 dp[0] = 1.0; 29 for (int i = 1; i < (1 << N); ++i){//表示任务完成情况,完成的位置标记成1 30 dp[i] = 0.0; 31 for (int j = 0; j < N; ++j){ 32 if (i&(1 << j)){ 33 dp[i] = max(dp[i], dp[i - (1 << j)] * data[num[i] - 1][j]); 34 //用前num[i]-1个人完成表示成i的任务 35 } 36 } 37 } 38 printf("#%d %.6lf\n", tc, dp[(1 << N) - 1] * 100.0); 39 } 40 return 0; 41 }