关于编程之美2014格格取数
个人感觉是ac了,只不过没有注册编程之美的号,所以没有办法测试,反正对于自己手写的几个例子都正确。这里偷了一下懒,就是把行数限制为64个以内,这样好做位操作。当然可以用两个长整型来表示,这样就可能比较麻烦了。有意愿的人自己去完善吧。核心思想是预处理加减枝加深搜,复杂度最坏指数级没办法。下面贴一下题目。
描述
给你一个m x n (1 <= m, n <= 100)的矩阵A (0<=aij<=10000),要求在矩阵中选择一些数,要求每一行,每一列都至少选到了一个数,使得选出的数的和尽量的小。
1 #include <iostream> 2 #include <stack> 3 #include <bitset> 4 #include <set> 5 6 using namespace std; 7 int current_sum=0; 8 int total_min = 0;//total_min是用来减枝,是全局最小的一个上限 9 int row_number; 10 int colomn_number; 11 int** int_matrix; 12 int* row_covered; 13 int row_left; 14 int colomn_left; 15 long long row_set[100]; 16 long long used_row_set[100]; 17 int temp_bitsum[100]; 18 int count_sum(long long row_bit_set, int current_colomn_number) 19 { 20 int temp_sum = 0; 21 int row_position = 0; 22 while (row_bit_set) 23 { 24 temp_sum += (row_bit_set%2) * int_matrix[row_position++][current_colomn_number]; 25 row_bit_set=row_bit_set >> 1; 26 } 27 return temp_sum; 28 } 29 int all_covered() 30 { 31 for (int i = 0; i < row_number; i++) 32 { 33 if (row_covered[i] == 0) 34 { 35 return 0; 36 } 37 } 38 return 1; 39 } 40 void dfs(int current_colomn) 41 { 42 long long temp_bitset = row_set[current_colomn]; 43 while (temp_bitset) 44 { 45 used_row_set[current_colomn] = temp_bitset; 46 temp_bitsum[current_colomn] = count_sum(temp_bitset, current_colomn); 47 if (current_sum + temp_bitsum[current_colomn] < total_min)//只有小于的时候才有必要进行下一次深度优先或者结束本次深度优先 48 { 49 current_sum = current_sum + temp_bitsum[current_colomn]; 50 for (int i = 0; i < row_number; i++)//对行进行mask 51 { 52 row_covered[i] += temp_bitset%2; 53 temp_bitset=temp_bitset >> 1; 54 } 55 if (current_colomn == colomn_number-1) 56 { 57 if (all_covered())//如果已经全部覆盖了,则表示这次深度优先搜索成功 58 { 59 total_min = current_sum ;//更新最小值 60 } 61 else//回溯,进行下一次试探 62 { 63 //什么都不需要干 64 } 65 //进行下一次试探 66 } 67 else 68 { 69 70 dfs(current_colomn + 1);//对下一列做dfs 71 } 72 temp_bitset = used_row_set[current_colomn]; 73 for (int i = 0; i < row_number; i++)//回溯 对行进行unmask 74 { 75 row_covered[i] -= temp_bitset % 2; 76 temp_bitset=temp_bitset >> 1; 77 } 78 current_sum -= temp_bitsum[current_colomn];//回溯 将和往回降 79 } 80 temp_bitset = used_row_set[current_colomn]; 81 temp_bitset = (temp_bitset - 1)&row_set[current_colomn]; 82 } 83 } 84 int main() 85 { 86 87 cout << "please enter the row number" << endl; 88 cin >> row_number; 89 cout << "please enter the colomn number" << endl; 90 //cin.get();//吃掉那一行,如果会换行的话 91 cin >> colomn_number; 92 cin.get(); 93 int_matrix = new int*[row_number]; 94 int_matrix[0] = new int[row_number*colomn_number]; 95 set<pair<int, int>> min_position; 96 for (int i = 1; i < row_number; i++) 97 { 98 int_matrix[i] = int_matrix[i - 1] + colomn_number; 99 } 100 for (int i = 0; i < row_number; i++) 101 { 102 for (int j = 0; j < colomn_number; j++) 103 { 104 cin >> int_matrix[i][j]; 105 } 106 } 107 //下面记录行最小值和列最小值是为了减枝用 108 int* row_min = new int[row_number]; 109 int* colomn_min = new int[colomn_number]; 110 for (int i = 0; i < row_number; i++)//寻找行最小值 111 { 112 row_min[i] = 0; 113 for (int j = 1; j < colomn_number; j++) 114 { 115 if (int_matrix[i][row_min[i]]>int_matrix[i][j]) 116 { 117 row_min[i] = j; 118 } 119 } 120 min_position.insert(make_pair(i, row_min[i])); 121 } 122 for (int i = 0; i < colomn_number; i++)//寻找列最小值 123 { 124 colomn_min[i] = 0; 125 for (int j = 1; j < row_number; j++) 126 { 127 if (int_matrix[colomn_min[i]][j]>int_matrix[j][i]) 128 { 129 colomn_min[i] = j; 130 } 131 } 132 min_position.insert(make_pair(colomn_min[i], i)); 133 } 134 for (auto temp_pair : min_position) 135 { 136 total_min += int_matrix[temp_pair.first][temp_pair.second]; 137 } 138 for (int i = 0; i < colomn_number; i++)//初始化行的位数组 139 { 140 row_set[i] = (1 << row_number) - 1; 141 } 142 for (int i = 0; i < row_number; i++) 143 { 144 for (int j = 0; j < colomn_number; j++) 145 { 146 if (int_matrix[i][j]>int_matrix[i][row_min[i]] + int_matrix[colomn_min[j]][j]) 147 { 148 row_set[j]=row_set[j]&(~(1<<i));//标记为不可用 149 } 150 } 151 } 152 //准备开始深度优先搜索 153 row_covered = new int[row_number]; 154 memset(row_covered, 0, sizeof(int) *row_number); 155 dfs(0); 156 cout << "current total min is " << total_min << endl; 157 }
样例数据和自己编的几组数据都过了,还待其他数据验证。