版权声明:欢迎大佬指正! 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 ;
}