Codeforces580D Kefa and Dishes
阿新 • • 發佈:2018-11-11
看完題目還是一臉蒙,百度了半天,看了好幾個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;
}