10.10
思路:
很明显能看出是dp,但是如果把dp函数定义成前i个房间有j的人就很难处理,这道题有种很好的解法是想象相邻房间都添加一个通道,然后将dp函数定义成通道经过的人的个数,知道前一个通道经过的人数和当前房屋的人数,就可以根据处理后房屋人数为0 4 7三种状态来更新之后的一条通道经过的人数以及代价。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define LL long long
#define N 100010
#define inf 1000000000000000
using namespace std;
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
int n;
LL dp[N][15], a[N];
LL ans = inf;
//dp[i][j]表示前i个屋子处理合法之后,要向外移出j-7个人的代价
//每个屋子原来最多就7个人,所以移动超过7人时完全可以丢7个在一个房间里
bool check(int t){//方案合法
if(t == 0 || t == 4 || t == 7) return true;
return false;
}
int main(){
freopen("hotel.in","r",stdin);
freopen("hotel.out","w",stdout);
scanf("%d", &n);
memset(dp, 0x3f, sizeof(dp));
for(int i=1; i<=n; i++) a[i] = read();
dp[0][7] = 0;//j==7表示不进不出
for(int i=0; i<n; i++)
for(int j=0; j<=14; j++)
if(dp[i][j] < inf){
int t = j - 7;//从i到i+1进来了t人(t<0就是出去了-t人)
for(int k=0; k<=14; k++){
int u = k - 7;//从i+1到i+2出去了t人
if( check( a[i+1] + t - u ) )//i+1房间中剩下的人
dp[i+1][k] = min(dp[i+1][k], dp[i][j] + abs(u));
}
}
for(int j=0; j<=14; j++)
if( check(a[n] + (j-7)) )
ans = min(ans, dp[n-1][j]);//只能统计合法方案
if(ans >= inf) printf("-1");
else printf("%d", ans);
return 0;
}