从左到右DP, 存储哪里有奶牛以后排序, 同一个x坐标的上下奶牛合并.. 0没有 1上 2下 3都有
随着奶牛的位置x从左到右DP, 需要记录的状态是dp[i][p][k], p是在x处的奶牛圈起来的方式, 我记的是 0没圈(这就初始状态可能) 1圈上 2圈下 3两个一起圈 4两个分开圈, 记录每个可能的k和对应的面积最小值
状态转移比较麻烦.. 我是又分两个状态之间的圈圈怎样互相结合来枚举, 0不结合 1上边延伸出去 2下边 3两边一起延伸 4两边分开延伸. 应该还有更巧妙的方法.. 不想再碰这题了
172ms 直接大数组20M内存..代码点下面
#include <stdio.h> #include <stdlib.h> #include <string.h> int adoptable(int p,int q) { if(p==3||p==4) return q==p?0:-1; if(p==1||p==2) { if(q==p) return 0; if(q==4) return 1; return -1; } //p==0; return q==0?0:q==4?2:1; } int ifAddK(int p0,int p1,int stretch) { if(adoptable(stretch,p0)==-1) return -1; return adoptable(stretch,p1); } int cmp(const void *_a, const void *_b) { int a=*(int *)_a,b=*(int *)_b; return (a>>3)-(b>>3); } int main() { int N,K,B; scanf("%d%d%d",&N,&K,&B); int map[1001]; for(int i=1;i<=N;i++) map[i]=-1; int mapN=0; for(int i=1;i<=N;i++) { int u,pos; scanf("%d%d",&u,&pos); int j; for(j=1;j<=mapN;j++) if( (map[j]>>3)==pos ) break; if(j>mapN) { map[j]= (pos<<3)|u; mapN++; } else map[j]|=u; } qsort(map+1,mapN,sizeof(int),cmp); int (*dp)[5][1001]; dp=(int (*)[5][1001])malloc(sizeof(int)*1001*5*1001); memset(dp[0],0xff,sizeof(dp[0])); dp[0][0][0]=0; map[0]=0; for(int i=1;i<=mapN;i++) { memset(dp[i],0xff,sizeof(dp[0])); for(int p0=0;p0<=4;p0++) //Statu of last for(int p1=0;p1<=4;p1++) // This state { if(p1!=4 && (p1|(map[i]&3))!=p1) continue; for(int stretch=0;stretch<=4;stretch++) //which side stretching { int addK=ifAddK(p0,p1,stretch); if(addK==-1) continue; int addC=(map[i]>>3)-(map[i-1]>>3)-1; addC*=(stretch==1||stretch==2)?1:stretch==0?0:2; addC+=(p1==0)?0:(p1==1||p1==2)?1:2; for(int k=0;k<=K;k++) { int k1=k+addK; if(k1>K) break; if(dp[i-1][p0][k]==-1) continue; if(dp[i][p1][k1]==-1||dp[i][p1][k1]>dp[i-1][p0][k]+addC) dp[i][p1][k1]=dp[i-1][p0][k]+addC; } } } } int result=2e9; for(int p=0;p<=4;p++) result=dp[mapN][p][K]!=-1&&dp[mapN][p][K]<result?dp[mapN][p][K]:result; printf("%d\n",result); return 0; }