Fancy Antiques(NAIPC 2016) 爆搜

版权声明:欢迎大佬指正! https://blog.csdn.net/sinat_36215255/article/details/82928732

题目网址https://nanti.jisuanke.com/t/32225

题意:

选择最多k个商店,买n个物品,求最小花费是多少。

思路:

 看的题解,急着走,先不自己写了。

这个人的剪枝方法的奇妙之处在于,先将商店排序,买的贵的先dfs。

1.通过提前求出,从当前这个商店直到后面的商店,每件物品的最小花费可以是多少,如果当前最小花费已经大于最优值,或者无法获得,那直接结束。

2.商店数超过k则结束。

就是那样一个排序后的dfs顺序,和加上minv数组提前预判,就可以让这个题目爆过去,真的很神奇。

还是太菜了。

代码:

#include <bits/stdc++.h>
using namespace std ;

typedef pair < int, int > pii ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 105 ;
const int INF = 0x3f3f3f3f ;

struct Node
{
    vector < pii > G ;
    int val ;
    //这个顺序,先搜大的,minv
    bool operator < ( const Node& a ) const
    {
        return val > a.val ;
    }
} ;

Node a[MAXN] ;
int minv[MAXN][MAXN] ;
int pre[MAXN] ;
int tmp[MAXN][MAXN] ;
int ans ;
int n, m, k ;

void dfs ( int cur, int num )
{
    int val = 0 ;
    for ( int i = 1 ; i <= n ; ++ i )
    {
        if (pre[i] == INF)
        {
            val = INF ;
            break ;
        }
        val += pre[i] ;
    }
    if ( val < ans )
        ans = val ;
    //超过k则返回
    if ( num >= k )
        return ;
    int tot = 0 ;
    //很重要的剪枝,如果后面没有更优的,那没有必要再搜索下去
    for ( int i = 1 ; i <= n ; ++ i )
    {
        if ( pre[i] == INF && minv[cur][i] == INF )
            return ;
        tot += min ( pre[i], minv[cur][i] ) ;
        if ( tot >= ans )
            return ;
    }
    for ( int i = cur ; i <= m ; ++ i )
    {
        for ( int j = 1 ; j <= n ; ++ j )
        {
            tmp[num][j] = pre[j] ;
        }
        for ( int j = 0 ; j < a[i].G.size () ; ++ j )
        {
            int x = a[i].G[j].first ;
            pre[x] = min (pre[x], a[i].G[j].second) ;
        }
        dfs ( i + 1, num + 1 ) ;
        for ( int j = 1 ; j <= n ; ++ j )
        {
            pre[j] = tmp[num][j] ;
        }
    }
}

void solve ()
{
    ans = INF ;
    for ( int i = 1 ; i <= m ; ++ i )
    {
        a[i].G.clear () ;
        a[i].val = 0 ;
    }
    for ( int i = 1 ; i <= n ; ++ i )
    {
        int x, p, y, q ;
        scanf ( "%d%d%d%d", &x, &p, &y, &q ) ;
        a[x].val ++ ;
        a[y].val ++ ;
        if ( p < q )
            a[x].val += 2 ;
        else
            a[y].val += 2 ;
        a[x].G.push_back ( pii ( i, p ) ) ;
        a[y].G.push_back ( pii ( i, q ) ) ;
    }
    sort ( a + 1, a + m + 1 ) ;
    for ( int i = 1 ; i <= n ; ++ i )
    {
        minv[m + 1][i] = INF ;
        pre[i] = INF ;
    }
    for ( int i = m ; i >= 1 ; -- i )
    {
        for ( int j = 1 ; j <= n ; ++ j )
        {
            minv[i][j] = minv[i + 1][j] ;
        }
        for ( int j = 0 ; j < a[i].G.size () ; ++ j )
        {
            int x = a[i].G[j].first, v = a[i].G[j].second ;
            minv[i][x] = min ( minv[i][x], v ) ;
        }
    }
    dfs ( 1, 0 ) ;
    printf ( "%d\n", ans == INF ? -1 : ans ) ;
}

int main ()
{
    while ( ~scanf ( "%d%d%d", &n, &m, &k ) )
        solve () ;
    return 0 ;
}

猜你喜欢

转载自blog.csdn.net/sinat_36215255/article/details/82928732
今日推荐