CF580D,Kefa and Dishes(状压DP)

题意:有n道菜,每道菜一个权值,有k个条件,表示第y道菜在第x道后马上吃有c的附加值。求从中吃m道菜的最大权值。

本题详解可看:
https://www.cnblogs.com/real-l/p/8597827.html
作为还在入门状压DP的萌新,这里就分析一下怎么推出DP状态。
首先,n的范围比较小,且每道菜有个吃与不吃操作,可用二进制1,0表示,故不难相处可用状压DP;其次,n道菜就有1<。最后,因为吃菜的顺序不同可能还有加成,因此我们还要记录一下上次吃的最后一道菜是什么。于是DP状态差不多就出来了:
状态:dp[i,j]表示在状态i的情况下,最后一道菜是吃j时所能达到的最大权值,1<=i<(1< 转移方程:
for( i <- 1 ~ 1< .----for( j <- 1 ~ n) //枚举在i状态下,最后吃的菜
.--------if( i & ( 1<< (j-1) ) )
.-----------for( k <- 1 ~ n) //枚举在i状态下,还没吃过的菜
.----------------if ( ! ( i & ( 1<< (k-1) ) )
.---------------------dp[i|(1<<(k-1),k]=max(dp[i|(1<<(k-1),k], dp[i,j]+a[k]+c[x,y]) //更新

不过因为题意有个限制,就是最终是要吃m道菜,显然,我们不可能再在DP状态中再加一维了,那样就太大了,如何解决这个问题会在代码中体现。

#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=1<<18;
ll dp[maxn][20];
ll a[20];
ll map[20][20];

int main()
{
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)	cin>>a[i];
	memset(map,0,sizeof(map));
	for(int i=1;i<=k;i++)
	{
		int x,y,c;
		cin>>x>>y>>c;
		map[x][y]=c;
	}
	memset(dp,0,sizeof(dp));
	ll ans=0;
	for(int i=1;i<=n;i++)	dp[1<<(i-1)][i]=a[i];
	for(int i=1;i<(1<

你可能感兴趣的:(状压DP,状压DP)