P3080 [USACO13MAR]The Cow Run G/S 题解


目录

    • 题面
    • 题目分析
        • 分析
        • 复杂度
    • 代码

题面

题面传送门


题目分析

分析

这是一道区间dp题。
这道题和P1220 关路灯特别相似,因为他们的状态转移方程都类似于
f [ l ] [ r ] [ 0 ] = m i n ( f [ l + 1 ] [ r ] [ 0 ] + 改 变 量 , f [ l + 1 ] [ r ] [ 1 ] + 改 变 量 ) f[l][r][0]=min( f[ l+1 ][ r ][ 0 ] +改变量 , f[ l+1 ][ r ][ 1 ] +改变量) f[l][r][0]=min(f[l+1][r][0]+,f[l+1][r][1]+
f [ l ] [ r ] [ 1 ] = m i n ( f [ l ] [ r − 1 ] [ 0 ] + 改 变 量 , f [ l ] [ r − 1 ] [ 1 ] + 改 变 量 ) f[l][r][1]=min( f[ l ][ r-1 ][ 0 ] +改变量 , f[ l ][ r-1 ][ 1 ] +改变量) f[l][r][1]=min(f[l][r1][0]+,f[l][r1][1]+
f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0] f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]表示当前已经套完了 i i i j j j的牛,然后用第三维表示在左边还是在右边。

我们把 n n n个点拆成 n + 1 n+1 n+1个点,找到 0 0 0点,设为 c c c,令 f [ c ] [ c ] [ 0 ] = f [ c ] [ c ] [ 1 ] = 0 f[c][c][0]=f[c][c][1]=0 f[c][c][0]=f[c][c][1]=0,其他的都为 0 x 3 f 0x3f 0x3f

我们下一步可以选择去 i − 1 i-1 i1,也就是下一步到 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j],或者选择去 j + 1 j+1 j+1,到 f [ i ] [ j + 1 ] f[i][j+1] f[i][j+1]
对于每一个当前的状态, a [ j ] a[j] a[j]可能在左边或者右边,也就是 f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]或者 f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0],每一个又有两种转移方案,于是我们可以把两个状态一起两重暴力进行转移。

其中 破 坏 量 = 距 离 ∗ 未 套 住 的 数 量 破坏量=距离*未套住的数量 =

复杂度

复杂度为 O ( n 2 ) O(n^2) O(n2)


代码

#include
#include
#include
#include			//养成好习惯,不用万能头
#define maxn 1039
using namespace std;
int n,f[maxn][maxn][2],a[maxn],c=0;
//inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}			//养成好习惯,手写min函数
inline int js(int x,int y,int l,int r){return (a[y]-a[x])*(n-r+l);}			//计算破坏量
int main(){
 	memset(f,0x3f,sizeof(f));
	register int i,j;
 	scanf("%d",&n);
 	for(i=1;i<=n;i++)  
		scanf("%d",a+i); 
	n++;	
	a[n]=0;			//把0塞在数组的最末端
	sort(a+1,a+n+1);			//排序
	for(i=1;i<=n;i++)			//找到0点
		if(!a[i]) c=i;
 	f[c][c][0]=f[c][c][1]=0; 
	for(j=c;j<=n;j++)			//区间dp
    	for(i=j-1;i>=1;i--){
    		f[i][j][0]=min(f[i+1][j][0]+js(i,i+1,i,j),f[i+1][j][1]+js(i,j,i,j));//套刚才推出的状态转移方程
    		f[i][j][1]=min(f[i][j-1][0]+js(i,j,i-1,j-1),f[i][j-1][1]+js(j-1,j,i-1,j-1));
		}
    printf("%d",min(f[1][n][0],f[1][n][1]));
    return 0;			//完美撒花
}

你可能感兴趣的:(洛谷,dp)