codeforces 793 D. Presents in Bankopolis(记忆化搜索)

题目链接:http://codeforces.com/contest/793/problem/D

题意:给出n个点m条边选择k个点,要求k个点是联通的而且不成环,而且选的边不能包含选过的边不能包含以前

选过的点,问最小的权值是多少。

题解:像这种取最小的一般可以考虑一下dp,然后再看一下题目,由于每次选的边都不能包括以前选的点,所以每

选择一条边能选择的区间范围就缩小了。

设dp[pos][l][r][k](这里可能会有人觉得开80*80*80*80会不会有点大了,自行计算一下不会爆内存的),pos表示当前位置,l表示区间左端点,r表示区间右端点,k表示还剩下多少条边没选当然也可以

设选了多少条边。附上记忆化搜索代码

int dfs(int pos , int l , int r , int count) {

    if(dp[pos][l][r][count] != -1) {

        return dp[pos][l][r][count];

    }

    if(count == 1) {

        dp[pos][l][r][count] = 0;

        return 0;

    }

    int sum = inf;

    for(int i = 1 ; i <= n ; i++) {

        if(mmp[pos][i] != inf) {

            if(i > l && i < r) {

                int sta = l , end = r;

                if(i < pos) {

                    end = pos;

                }

                else {

                    sta = pos;

                }

                sum = min(sum , dfs(i , sta , end , count - 1) + mmp[pos][i]);

            }

        }

    }

    dp[pos][l][r][count] = sum;

    return sum;

}

#include <iostream>
#include <cstring>
#include <cstdio>
#define inf 0X3f3f3f3f
using namespace std;
const int M = 82;
int n , k , m , u , v , c;
int mmp[M][M] , dp[M][M][M][M];
int dfs(int pos , int l , int r , int count) {
    if(dp[pos][l][r][count] != -1) {
        return dp[pos][l][r][count];
    }
    if(count == 1) {
        dp[pos][l][r][count] = 0;
        return 0;
    }
    int sum = inf;
    for(int i = 1 ; i <= n ; i++) {
        if(mmp[pos][i] != inf) {
            if(i > l && i < r) {
                int sta = l , end = r;
                if(i < pos) {
                    end = pos;
                }
                else {
                    sta = pos;
                }
                sum = min(sum , dfs(i , sta , end , count - 1) + mmp[pos][i]);
            }
        }
    }
    dp[pos][l][r][count] = sum;
    return sum;
}
int main() {
    scanf("%d%d" , &n , &k);
    scanf("%d" , &m);
    memset(mmp , inf , sizeof(mmp));
    for(int i = 0 ; i < m ; i++) {
        scanf("%d%d%d" , &u , &v , &c);
        mmp[u][v] = min(mmp[u][v] , c);
    }
    memset(dp , -1 , sizeof(dp));
    int ans = inf;
    for(int i = 1 ; i <= n ; i++) {
        ans = min(ans , dfs(i , 0 , n + 1 , k));
    }
    if(ans == inf) {
        printf("-1
");
    }
    else {
        printf("%d
" , ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/6758247.html