D. Kefa and Dishes

D. Kefa and Dishes

题目链接
给一个序列ai,长度为n,每个ai对应一个价值,选出m个数字出来,同时给出K对关系(i,j,ck)表示当前如果取了第j个,而上次是取的第i个,那么还可以获得ck的价值,问最大能获得的价值。
m<=n<=18
看似一个图论,网络流之类的流来流去,但是数据范围较小,可以直接状压dp。
f[i][status][j]表示当前取了i个状态为status,且当前取的是第j个数字,然后从f[i-1][status^(2的j次方)][k]去转移就行了

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const LONG  MOD=1e9+ 7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson  l , mid , rt<< 1
#define rson  mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
LONG  f[2][(1<<18)+50][20];
vector<int> vec[25];
LONG  a[20] ;
LONG  Map[20][20] ;
int main()
{
    int n, m, K;
    scanf("%d%d%d",&n,&m,&K) ;
    for(int i =0 ; i <= 20 ; ++ i)
        vec[i].clear() ;
    for(int i = 0 ; i < (1<for(int i = 1; i <= n ; ++ i)
        scanf("%lld",&a[i]) ;
    for(int i = 1; i <=K ; ++ i)
    {
        int u,v ;
        LONG val ;
        scanf("%d%d%lld",&u,&v,&val) ;
        Map[v][u] = max(Map[v][u] , val ) ;
    }
    for(int i = 0 ;i 1][1<1] = a[i+1] ;
    for( int i = 2; i<= m; ++ i)
    {
        for(int j = 0 ; j int now = vec[i][j] ;
            int tmp = now ;
            for(int k = 0 ;k < n ; ++k )
                for(int l = 0 ; l < n ; ++ l)
                    if( (now>>k&1) &&(now>>l&1) )
                    f[i&1][now][k+1] = max(f[i&1][now][k+1] , f[!(i&1)][now^(1<1] + Map[k+1][l+1] + a[k+1]) ;
        }
    }
    LONG ans =0 ;
    for(int i= 0 ; i < vec[m].size() ; ++ i)
    {
        int now = vec[m][i] ;
        for(int j = 1 ; j <= n ; ++ j)
            ans = max(ans , f[ (m&1) ][now][j]) ;
    }
    printf("%lld\n",ans) ;
    return 0 ;
}

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