标签:class 地方 char while 交换 bit clu scanf bsp
题面:
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; }
标签:class 地方 char while 交换 bit clu scanf bsp
原文地址:https://www.cnblogs.com/lyflalala/p/11379462.html