FZU 2120-數字排列(狀壓DP)
阿新 • • 發佈:2018-11-22
S得到了一個數,他認為相鄰位上的數字與數字之間會產生不良影響,比如123,1和2之間產生一個不良影響值,2和3之間產生一個不良影響值。現在他想調整這個數每位的數字的順序,使得最終得到的數的總的不良影響值最小,且沒有前導0。
Input輸入資料的第一行為T表示有T組資料。每組資料先輸入一個整數n(0<n<1000000000),接下來輸入10*10的矩陣,Aij表示數字i與數字j相鄰產生的不良影響值,0<Aij<1000000,矩陣是對稱的,Aij與Aji相等。
Output對於每組資料輸出一行一個數,表示最小的不良影響值。
Sample Input1 123 0 0 0 0 0 0 0 0 0 0 0 0 10 1 0 0 0 0 0 0 0 10 0 2 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3
思路:列舉型別的題目,二進位制表示其是否訪問過,顯然的狀壓DP。dp[i][j]表示i狀態以j結尾。方程:dp[nx][i] = min(dp[nx][i],dp[x][y]+map[num[y]-'0'][num[i]-'0']);
#include <stdio.h> #include <string.h> #include <ctime> #include <stack> #include <string> #include <algorithm> #include <iostream> #include <cmath> #include <queue> #include <vector> using namespace std; #define LL long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lowbit(x) (x&-x) const int maxn = 2005; const int INF = 0x3f3f3f3f; char num[15]; int len; int map[12][12]; int dp[maxn][12]; bool vis[maxn][12]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",num); len = strlen(num); for(int i=0; i<10; i++) for(int j=0; j<10; j++) { scanf("%d",&map[i][j]); } memset(dp,INF,sizeof(dp)); memset(vis,0,sizeof(vis)); queue<pair<int,int> > q; for(int i=0; i<len; i++) { if(num[i]!='0') { dp[1<<i][i] = 0; q.push(make_pair(1<<i,i)); } } while(!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); for(int i=0; i<len; i++) { if((x&(1<<i))==0) { int nx = x|(1<<i); dp[nx][i] = min(dp[nx][i],dp[x][y]+map[num[y]-'0'][num[i]-'0']); if(!vis[nx][i]) { vis[nx][i] = true; q.push(make_pair(nx,i)); } } } } int ans = INF,n=1<<len; for(int i=0; i<len; i++) ans = min(ans,dp[n-1][i]); cout<<ans<<endl; } return 0; }