题目描述
kefa进入了一家餐厅,这家餐厅中有n个菜(0<n<=18),kefa对第i个菜的满意度为ai(0<=ai<=10^9),并且对于这n个菜有k个规则,如果kefa在吃完第xi个菜之后吃了第yi个菜(保证xi、yi不相等),那么会额外获得ci(0<=ci<=10^9)的满意度。kefa要吃m道任意的菜(0<m<=n),但是他希望自己吃菜的顺序得到的满意度最大,请你帮帮kefa吧!
输入
第一行是一个数n
第二行是n个数,第i个数表示kefa对第i道菜的满意度为ai
第三行到第k+2行每行有3个数:xi,yi,ci,表示如果kefa在吃完第xi道菜之后立刻吃了第yi道菜,则会额外获得ci的满意度
输出
一行一个数表示最大满意度
样例输入
4 3 2 1 2 3 4 2 1 5 3 4 2
样例输出
12
题解
状压dp。
设dp[ s ][ i ] 表示当前状态为 s,最后一个吃的菜是 i 获得的最大满意度。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=18+5; const int maxm=(1<<18)+5; ll n,m,k,ad[maxn][maxn],a[maxn]; ll dp[maxm][maxn],cnt,ans; template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int count(int x){ int ret=0; while(x){ ret++;x&=x-1; } return ret; } int main(){ read(n),read(m),read(k); for(int i=1;i<=n;i++){ read(a[i]); dp[1<<i-1][i]=a[i]; } for(int i=1;i<=k;i++){ ll x,y,z; read(x),read(y),read(z); ad[x][y]=z; } for(int s=0;s<(1<<n);s++){ for(int i=1;i<=n;i++){ if(!(s&(1<<i-1))) continue; for(int j=1;j<=n;j++){ if(j==i||!(s&(1<<j-1))) continue; dp[s][j]=max(dp[s][j],dp[s^(1<<j-1)][i]+a[j]+ad[i][j]); } } } for(int s=0;s<(1<<n);s++) if(count(s)==m){ for(int i=1;i<=n;i++){ if(!(s&(1<<i-1))) continue; ans=max(ans,dp[s][i]); } } cout<<ans<<endl; return 0; }