Codeforces 580D Kefa and Dishes

題目鏈接

題意:

n個點 m條有向邊 選恰好k個點

下面n個數給出點權

下面m行給出邊和邊權

設上一次選的點是u這一次選的點是v,則可以獲得邊權u->v的價值

問:使得選出的權和最大,問最大的權和

思路:顯然是狀壓dp,每個點只有兩種情況,選或者不選,

dp[i][j]表示選的點狀態爲i,最後一次選的點是j的最大價值。

狀態轉移方程:dp[(1 << k) ^ i][k + 1] = max(dp[i][t + 1] + val[t + 1][k + 1] + a[k], dp[(1 << k) ^ i][k + 1])

代碼如下:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1 << 19;
int n, m, k;
int a[20], val[20][20];
ll dp[N][20]; //dp[i][j] 狀態爲i,最後一個吃掉的是j的最大愉悅度 

int main()
{
	while(~scanf("%d%d%d", &n, &m, &k))
	{
		for(int i = 0; i < n; i++)
		{
			scanf("%d", &a[i]);
		}
		memset(val, 0, sizeof(val));
		while(k--)
		{
			int x, y, c;
			scanf("%d%d%d", &x, &y, &c);
			val[x][y] = c;
		}
		ll ans = 0;
		for(int i = 0; i < n; i++)
		{
			dp[1<<i][i+1] = a[i];
			ans = max(ans, (ll)(a[i]));
		}
		for(int i = 0; i < (1 << n); i++)
		{
			int tmp[20], sz = 0;  
	        for(int j = 0; j < n; j++) 
			{  
	            if((1 << j) & i) tmp[sz++] = j;  
	        }  
	        if(sz >= m) continue;  
	        for(int k = 0; k < n; k++) 
			{  
	            if(((1 << k) & i) == 0) 
				{  
	                for(int j = 0; j < sz; j++) 
					{  
	                    int t = tmp[j];  
	                    dp[(1 << k) ^ i][k + 1] = max(dp[i][t + 1] + val[t + 1][k + 1] + a[k], dp[(1 << k) ^ i][k + 1]);  
	                    if(sz == m-1) 
						{  
	                        ans = max(dp[(1 << k) ^ i][k + 1], ans);  
	                    }  
	                }  
	            }  
	        }  
		} 
		printf("%I64d\n", ans);	
	}
	return 0;
}

發佈了102 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章