街道灯光

时间:2019-08-19
本文章向大家介绍街道灯光,主要包括街道灯光使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题面:

  n盏灯,每盏灯可以点亮自己和与它相邻的灯,点亮第i盏灯的代价为 w[i] ,你有k次强行交换两盏灯花费的机会,问照亮整个街道的最小花费。

输入:第一行:n,k

   第二行:w[1]~w[n]

输出:最小代价

题解:设dp [i] [x] [y] [a] [b]表示考察了前 i盏灯,最后两盏灯的亮灭状态分别为 x,y,已经有 a 盏亮的灯被换走了,已经有 b 盏灭的灯被换上的最小代价。

   只有四种转移:点灯;不点灯;点亮后被换走;不点从别的地方弄个灯过来。复杂度 O(nk2)。

   ‘灯点亮被换走’转移时加上代价,‘从别的地方弄个灯过来’不花代价,,最后只要看 a=b 的 dp数组就可以了

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
inline ll read()
{
    char ch=getchar();
    int s=0,f=0;
    while(!(ch<='9'&&ch>='0')) {f|=ch=='-';ch=getchar();}
    while(ch<='9'&&ch>='0') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return f?-s:s;
}
const int K = 10;
const int N = 250005;
const long long INF = 1e17;
int n, k;
int w[N];
//考察了前 i盏灯,最后两盏灯的亮灭状态分别为 x,y,已经有 a 盏亮的灯被换走了,已经有 b 盏灭的灯被换上了的最小代价,

long long dp[2][2][2][K][K];
int main() 
{
    freopen("light.in","r",stdin);
    freopen("light.out","w",stdout);
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) 
      w[i] = read();
    
    memset(dp, 0x3f, sizeof dp);
    dp[0][1][0][0][0] = 0;
    for (int i = 0; i < n; ++i)
        {
      int nxt = ~i & 1, pre = i & 1, val = w[i + 1];
      memset(dp[nxt], 0x3f, sizeof dp[nxt]);
      for (int a = 0; a <= k; ++a)
        for (int b = 0; b <= k; ++b)
          for (int x = 0; x < 2; ++x)
            for (int y = 0; y < 2; ++y)
                        {
                if (dp[pre][x][y][a][b] > INF) continue;
                dp[nxt][y][1][a][b]=min(dp[nxt][y][1][a][b],dp[pre][x][y][a][b] + val);//点亮这盏灯 
            
                if (x || y)//这盏灯不点 
                    dp[nxt][y][0][a][b]=min(dp[nxt][y][0][a][b], dp[pre][x][y][a][b]);
                if (b < k)//有资格被资助
                    dp[nxt][y][1][a][b + 1]=min(dp[nxt][y][1][a][b + 1], dp[pre][x][y][a][b]);
                if (a < k && (x || y))//有资格资助别人 
                    dp[nxt][y][0][a + 1][b]=min(dp[nxt][y][0][a + 1][b], dp[pre][x][y][a][b] + val);
            }
    }

    long long ans = INF;
    for (int i = 0; i <= k; ++i) 
      for (int x = 0; x < 2; ++x) 
        for (int y = 0; y < 2; ++y) 
          if (x || y) 
              ans = min(ans, dp[n & 1][x][y][i][i]);
 
    printf("%lld\n", ans);
  
    return 0;
}

原文地址:https://www.cnblogs.com/lyflalala/p/11379462.html