演算法提高 金陵十三釵
阿新 • • 發佈:2019-02-09
Problem Description
在電影《金陵十三釵》中有十二個秦淮河的女人要自我犧牲代替十二個女學生去赴日本人的死亡宴會。為了不讓日本人發現,自然需要一番喬裝打扮。但由於天生材質的原因,每個人和每個人之間的相似度是不同的。由於我們這是程式設計題,因此情況就變成了金陵n釵。給出n個女人和n個學生的相似度矩陣,求她們之間的匹配所能獲得的最大相似度。
所謂相似度矩陣是一個n*n的二維陣列like[i][j]。其中i,j分別為女人的編號和學生的編號,皆從0到n-1編號。like[i][j]是一個0到100的整數值,表示第i個女人和第j個學生的相似度,值越大相似度越大,比如0表示完全不相似,100表示百分之百一樣。每個女人都需要找一個自己代替的女學生。
最終要使兩邊一一配對,形成一個匹配。請程式設計找到一種匹配方案,使各對女人和女學生之間的相似度之和最大。
Input
第一行一個正整數n表示有n個秦淮河女人和n個女學生
接下來n行給出相似度,每行n個0到100的整數,依次對應二維矩陣的n行n列。
Output
僅一行,一個整數,表示可獲得的最大相似度。
Sample Input
4
97 91 68 14
8 33 27 92
36 32 98 53
73 7 17 82
Sample Output
354
思路
狀態壓縮DP
因為最多隻有13個學生,每個學生用一位二進位制表示,可以壓縮成一個整數
例如1010 (大->小) 可以表示配對了第二個第四個學生
將學生的下標從0開始計數比較方便,這樣1<< i就代表第i個學生了。
可以根據配對了幾個學生選擇第幾個女人來配對,這樣就能降一維了。
例如:1010配對了兩個學生,可以由第一個女人和第二個學生配對轉移過來,也可以由第一個女人和第四個學生轉移過來
AC程式碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[15][15], dp[8200];
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL),cout.tie(NULL);
int n;
cin>>n;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin>>a[i][j];
for (int S = 1; S < (1<<n); S++) //列舉所謂配對情況
{
int tmp = S, i = -1; //i表示有幾個學生配對,下標從0開始
while (tmp)
{
i++;
tmp -= tmp&-tmp;
}
for (int j = 0; j < n; j++)
if (S & (1<<j)) //讓第i個女人和第j個學生配對
dp[S] = max(dp[S], dp[S^(1<<j)] + a[i][j]);
}
cout<<dp[(1<<n)-1]<<endl;
return 0;
}