Fancy Antiques(NAIPC 2016) 爆搜

題目網址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 ;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章