zoukankan      html  css  js  c++  java
  • leetcode 1879.两个数组最小的异或值之和 模拟退火 KM 状压dp

    给你两个整数数组 nums1 和 nums2 ,它们长度都为 n 。

    两个数组的 异或值之和 为 (nums1[0] XOR nums2[0]) + (nums1[1] XOR nums2[1]) + ... + (nums1[n - 1] XOR nums2[n - 1]) (下标从 0 开始)。

    • 比方说,[1,2,3] 和 [3,2,1] 的 异或值之和 等于 (1 XOR 3) + (2 XOR 2) + (3 XOR 1) = 2 + 0 + 2 = 4 。

    请你将 nums2 中的元素重新排列,使得 异或值之和 最小 。

    请你返回重新排列之后的 异或值之和 。

    示例 1:

    输入:nums1 = [1,2], nums2 = [2,3]
    输出:2
    解释:将 nums2 重新排列得到 [3,2] 。
    异或值之和为 (1 XOR 3) + (2 XOR 2) = 2 + 0 = 2 。

    示例 2:

    输入:nums1 = [1,0,3], nums2 = [5,3,4]
    输出:8
    解释:将 nums2 重新排列得到 [5,4,3] 。
    异或值之和为 (1 XOR 5) + (0 XOR 4) + (3 XOR 3) = 4 + 4 + 0 = 8 。
    

    提示:

    • n == nums1.length
    • n == nums2.length
    • 1 <= n <= 14
    • 0 <= nums1[i], nums2[i] <= 107

    首先是模拟退火,每次交换nums2中的两个位置的值进行模拟退火,最终将退火中计算得出的最小值作为答案。

     1 class Solution {
     2 public:
     3     int minimumXORSum(vector<int>& nums1, vector<int>& nums2) {
     4         int n = nums2.size();
     5         random_shuffle(nums2.begin(),nums2.end());
     6         int t = 0,dt = 0;
     7         for(int i=0;i<n;i++)
     8             t += nums1[i] ^ nums2[i];
     9         int ans = t;
    10         for(double T = 1e6;T > 1e-18;T *= 0.999){
    11             int x = rand() % n,y = rand() % n;
    12             dt = - (nums1[x] ^ nums2[x]) - (nums1[y] ^ nums2[y]) + (nums1[x] ^ nums2[y]) + (nums1[y] ^ nums2[x]);
    13             ans = min(ans,t + dt);
    14             if(dt < 0){
    15                 t += dt;
    16                 swap(nums2[x],nums2[y]);
    17             }else if(exp(-1.0 * dt / T) * RAND_MAX > rand()){
    18                 t += dt;
    19                 swap(nums2[x],nums2[y]);
    20             }
    21         }
    22         return ans;
    23     }
    24 };
    View Code

    其次是KM算法求二分图的最小权匹配,将nums1和nums2中的每个元素之间都建边,边值为两者异或结果的相反数,然后跑KM算法求二分图的最大权匹配即可。

     1 class Solution {
     2 public:
     3     vector<vector<int> > wei;
     4     int n;
     5     vector<int> visx, visy, linky, lx, ly;
     6     int xnum, ynum;
     7     int findPath(int now){
     8         visx[now] = 1;
     9         for(int i=0;i<ynum;i++){
    10             if(!visy[i] && lx[now] + ly[i] == wei[now][i]){
    11                 visy[i] = 1;
    12                 if(linky[i] == -1 || findPath(linky[i])){
    13                     linky[i] = now;
    14                     return 1;
    15                 }
    16             }
    17         }
    18         return 0;
    19     }
    20     int km(){
    21         linky = vector<int> (ynum,-1);
    22         ly = vector<int> (ynum,0);
    23         lx = vector<int> (xnum,-0x3f3f3f3f);
    24         for(int i=0;i<xnum;i++){
    25             for(int j=0;j<ynum;j++){
    26                 lx[i] = max(lx[i],wei[i][j]);
    27             }
    28         }
    29         for(int i=0;i<xnum;i++){
    30             while(1){
    31                 visx = vector<int> (xnum,0);
    32                 visy = vector<int> (ynum,0);
    33                 if(findPath(i))  break;
    34                 int d = 0x3f3f3f3f ;
    35                 for(int j=0;j<xnum;j++)
    36                     if(visx[j])
    37                         for(int k=0;k<ynum;k++)
    38                             if(!visy[k])
    39                                 d = min(d,lx[j] + ly[k] - wei[j][k]);
    40                 if(d == 0x3f3f3f3f) return -1;
    41                 for(int j=0;j<xnum;j++)  if(visx[j])  lx[j] -= d;
    42                 for(int j=0;j<ynum;j++) if(visy[j]) ly[j] += d;
    43             }
    44         }
    45         int ans = 0;
    46         for(int i=0;i<ynum;i++){
    47             if(linky[i] > -1) ans += -wei[linky[i]][i];
    48         }
    49         return ans;
    50     }
    51     int minimumXORSum(vector<int>& nums1, vector<int>& nums2) {
    52         n = nums1.size();
    53         xnum = n,ynum = n;
    54         wei = vector<vector<int> > (n,vector<int> (n,0));
    55         for(int i=0;i<n;i++){
    56             for(int j=0;j<n;j++){
    57                 wei[i][j] = - (nums1[i] ^ nums2[j]);
    58             }
    59         }
    60         return km();
    61     }
    62 };
    View Code

    然后是官方正解,也就是状态压缩dp,官方解如下

     1 class Solution {
     2 public:
     3     int minimumXORSum(vector<int>& nums1, vector<int>& nums2) {
     4         int n = nums1.size(),m = 1 << n;
     5         vector<int> f(m,INT_MAX);
     6         f[0] = 0;
     7         for(int mask=1;mask<m;mask++){
     8             for(int i=0;i<n;i++){
     9                 if(mask & (1 << i)){
    10                     f[mask] = min(f[mask],f[mask ^ (1 << i)] + (nums1[ __builtin_popcount(mask) - 1] ^ nums2[i]));
    11                 }
    12             }
    13         }
    14         return f[m - 1];
    15     }
    16 };
    View Code
  • 相关阅读:
    Android SharedPreferences 简单使用
    Android Broadcast广播
    Android Service 的生命周期
    Android RecyclerView的使用
    Android ListView addHeaderView()、addFooterView()和变更列表
    Android ListView的缓存机制
    Android ViewPager + Fragment的实现与Fragment生命周期管理
    Android 触摸事件的传递过程
    Java 泛型及相关使用
    android 常用View的一些注意点(CheckedTextView)
  • 原文地址:https://www.cnblogs.com/wujiechao/p/14842947.html
Copyright © 2011-2022 走看看