题目地址:http://acm.uestc.edu.cn/problem.php?pid=1693&cid=167
dp[i][j]表示前i点加入j个好人收到的最小代价。
dp[i][j] = min( 第i点不加入好人的代价, 第i点加个好人的代价 );
其中
第i点不加好人的代价 t1 = dp[i-1][j] + ((i-j)==1 && i%10==0)?1:0;
第i点加好人的代价 t2 = dp[i-1][j-1] + i%10==0?1:0;
转移时注意某种转移能否进行哟~
然后在选择最小的之后,记录是由i-1个位子哪个j转移来的。最后从后往前找直接可以得解。
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #define sf scanf #define pf printf #define pfn printf("\n"); #define ll long long #define INF 0x7fffffff using namespace std; struct { int c,j; } dp[10051][51]; int n,k,a[10001],stack[100],top,ans; void ini() { for(int i=1; i<=n+k; i++) for(int j=0; j<=k; j++) dp[i][j].c=INF;} void DP(){ int i,j,t1,t2; dp[1][0].c=0; dp[1][1].c=0; for(i=2; i<=n+k; i++){ for(j=0; j<=k; j++){ if(j>i) break; if(dp[i-1][j].c!=EOF){ if(i%10==0 && a[i-j]==1) t1 = dp[i-1][j].c+1; else t1 = dp[i-1][j].c; } else t1 = INF; if(j>0){ if(i%10==0) t2 = dp[i-1][j-1].c+1; else t2 = dp[i-1][j-1].c; } else t2=INF; if(t1<=t2){ dp[i][j].c=t1; dp[i][j].j=j; } else{ dp[i][j].c=t2; dp[i][j].j=j-1; } } } } void print(int i,int j){ top=0; while(i>1){ if(dp[i][j].j!=j) stack[top++]=i; j=dp[i][j].j; i--; } if(j==1) stack[top++]=1; cout<<top; while(top>0) pf(" %d",stack[--top]); } int main() { int ii,jj; char s[10],ch; while(sf("%d %d",&n,&k)!=EOF){ gets(s); for(int i=1; i<=n; i++){ scanf("%c",&ch); if(ch=='0') a[i]=0; else a[i]=1; } ini(); DP(); ans=INF; for(int i=n; i<=n+k; i++) for(int j=0; j<=k; j++) { if(i-j==n && dp[i][j].c<ans) { ans=dp[i][j].c; ii=i; jj=j;}} pf("%d\n",ans); print(ii,jj); pfn } return 0; }