1. 程式人生 > >Codeforces580D Kefa and Dishes

Codeforces580D Kefa and Dishes

看完題目還是一臉蒙,百度了半天,看了好幾個AC程式碼才勉強寫(湊)出來。
題意很簡單,選單上有n道菜,你可以點m樣,每樣菜有它自己的幸福感,然後還加入了k個規則,比如在吃了第i樣菜之後,再吃第j樣菜,可以獲得c的幸福感,問最大的幸福感。
1<=m<=m<=18 c<=1e9
因為是DP專題,肯定是用DP來寫,但是始終找不到頭緒。百度了一下,需要儲存兩個狀態,一是現在所有菜的選擇狀態,二是選擇的最後一道菜是什麼菜。特殊規則就用鄰接矩陣來存就可以了。
菜的選擇狀態可以用二進位制來儲存。2的18次方,也不是很大。令s為所有菜的儲存狀態,於是可以寫出狀態轉移方程。
寫出轉移方程就很簡單了。一遍下來,就一個錯誤,在一個位運算的地方忘了加括號了,因為位運算的優先順序很低,幾乎每用一次位運算,都應該加括號。

//Dp[s|(1<<j)][j]=max(Dp[s|(1<<j)][j],Dp[s][i]+ans[j]+Map[i][j];
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=20;
const int maxnn=(1<<18)+10;
ll ans[maxn]={0};
ll Map[maxn][maxn]={0};
ll dp[maxnn][maxn]={0};
ll MAX=0;
int m,n,k;
int main()
{
    cin
>
>n>>m>>k; for(int i=0;i<n;i++) { cin>>ans[i]; } while(k--) { int a,b,c; cin>>a>>b>>c; Map[a-1][b-1]=c; } for(int i=0;i<n;i++) { dp[(1<<i)][i]=ans[i]; } ll tal=(1<<n);
for(int s=0;s<tal;s++) { int vvv=0; for(int i=0;i<n;i++) { if((s&(1<<i))!=0) { vvv++; for(int j=0;j<n;j++) { if((s&(1<<j))==0) { int ss=(s|(1<<j)); dp[ss][j]=max(dp[ss][j],dp[s][i]+ans[j]+Map[i][j]); } } } } if(vvv==m) { for(int i=0;i<n;i++) { if((s&(1<<i))!=0) { MAX=max(MAX,dp[s][i]); } } } } cout<<MAX<<endl; }