zoukankan      html  css  js  c++  java
  • 街道灯光

    题面:

      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
    ", ans);
      
        return 0;
    }
  • 相关阅读:
    面向对象之设计模式大全
    JDK各版本新增的主要特性
    迷宫最短路径-货郎担问题的解决思路
    详细介绍Java垃圾回收机制
    并发编程与任务建模
    淘宝npm镜像使用方法
    Metrics-Java版的指标度量工具
    Velocity基本语法
    Git之”make sure you have the correct access…”
    Mysql的转义字符
  • 原文地址:https://www.cnblogs.com/lyflalala/p/11379462.html
Copyright © 2011-2022 走看看