1. 程式人生 > >最小總代價 狀壓DP

最小總代價 狀壓DP

題目描述

  n個人在做傳遞物品的遊戲,編號為1-n。
  遊戲規則是這樣的:開始時物品可以在任意一人手上,他可把物品傳遞給其他人中的任意一位;下一個人可以傳遞給未接過物品的任意一人。即物品只能經過同一個人一次,而且每次傳遞過程都有一個代價;不同的人傳給不同的人的代價值之間沒有聯絡;
  求當物品經過所有n個人後,整個過程的總代價是多少。

資料範圍

(2<=n<=16)

樣例輸入

2
-1 9794
2724 –1

樣例輸出

2724

解題思路

  這個資料範圍很容易讓人想到爆搜或者是狀壓什麼的。但是如果是爆搜,我只會n!的做法,所以應該不是爆搜,於是就開始寫狀壓。之後十分天真地寫出了一個錯誤的狀壓。
↓↓↓這就是我原來的錯誤程式碼↓↓↓

#include <bits/stdc++.h>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int main(){
    int Map[17][17],f[65536];
    int n=Getint();
    for
(int i=1;i<=n;i++) for(int j=1;j<=n;j++) Map[i][j]=Getint(); memset(f,0x3f,sizeof(f)); for(int i=1;i<=n;i++) f[1<<(i-1)]=0; for(int i=0;i<(1<<n);i++){ for(int j=1;j<=n;j++){ if(i&(1<<(j-1))) continue
; for(int k=1;k<=n;k++) if(i&(1<<(k-1))) f[i+(1<<(j-1))]=min(f[i+(1<<(j-1))],f[i]+Map[k][j]); } } cout<<f[(1<<n)-1]; return 0; }

  很顯然,這一份程式碼根本就沒有記錄當前狀態是來自何處,於是求出來的答案並不滿足條件。但是,我當我用這個錯誤的程式過了樣例之後就果斷交上了我們學校的OJ。。。而且,,,居然有85分。。。。
  之後就寫了一個n階乘暴力,然後對拍,發現n=3都會很容易錯,調了一下,發現了問題,之後訂正後再交,就AC了。。其實最後還被<<這個的優先順序坑了一下。。

(其實上面的都是廢話,QAQ)

f[i][j]表示什麼怎麼轉移就直接看程式碼吧。。。

程式碼

#include <bits/stdc++.h>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int Map[17][17],f[65536][17];
int main(){
    int n=Getint();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            Map[i][j]=Getint();
    for(int i=0;i<(1<<n);i++)
        for(int j=1;j<=n;j++)
            f[i][j]=1<<30;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            f[1<<(i-1)][j]=1<<30;
        f[1<<(i-1)][i]=0;
    }
    for(int i=1;i<(1<<n);i++)
        for(int j=1;j<=n;j++){
            if(i&(1<<(j-1)))continue;
            for(int k=1;k<=n;k++)
                if(f[i][k]!=1<<30)
                    f[i|1<<(j-1)][j]=min(f[i|1<<(j-1)][j],f[i][k]+Map[k][j]);
        }
    int Min=1<<30;
    for(int i=1;i<=n;i++)
        Min=min(Min,f[(1<<n)-1][i]);
    cout<<Min;
    return 0;
}