P1220 关路灯
传送门
思路:
很明显的区间动规。设 f [ i ][ j ][ k ] 表示从 i ~ j 的路灯全部关闭时,老张所处的位置[( k=0,处在 i 处),( k=1,处在 j 处)]。
△则可以得出转移方程式有:
f [ i ][ j ][ 0 ] = min ( f [ i+1 ][ j ][ 0 ] + cal() , f [ i+1 ][ j ][ 1 ] + cal() );
f [ i ][ j ][ 1 ] = min ( f[ i ][ j-1 ][ 0 ] + cal() , f[ i ][ j-1 ][ 1 ] + cal() );
注:cal() — 伪代码,计算从上一个区间转移过来时没关的路灯消耗的电力。
标程:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #include<string> #include<vector> #include<stack> #include<map> #include<set> #include<queue> #include<deque> using namespace std; #define maxn 60 #define INF 0x3f int sum[maxn],a[maxn],b[maxn];//a记录位置,b记录功率 int f[maxn][maxn][2]; int n,c; inline int read() { int kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(!(ls^45)) kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } int main() { n=read();c=read(); for(int i=1;i<=n;i++) { a[i]=read();b[i]=read();//读入这个灯的距离,功率 sum[i]=sum[i-1]+b[i];//可以利用前缀和快速查找到从 i ~ j 的功率和(下方动规转移要用) } memset(f,INF,sizeof(f)); f[c][c][0]=f[c][c][1]=0;//刚开始老张所处的点直接清零 for(int l=2;l<=n;l++)//枚举区间长度 for(int i=1;i+l-1<=n;i++)//枚举左端点 { int j=i+l-1; f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[i]+sum[n]-sum[j]),f[i+1][j][1]+(a[j]-a[i])*(sum[i]+sum[n]-sum[j])); f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[i-1]+sum[n]-sum[j-1]),f[i][j-1][1]+(a[j]-a[j-1])*(sum[i-1]+sum[n]-sum[j-1]));//可以参考伪代码 } printf("%d\n",min(f[1][n][0],f[1][n][1]));//输出 return 0; }