题目链接:http://codeforces.com/contest/339/problem/C
题目大意:
在天平上放砝码
你要在左边放一下然后到右边放一下
一直重复这样放m次
每次你放在其中一边都要让另外一边的重量比你少
你可以用1~10中的某些砝码
问你要怎样放才行,或者告知系统不能放m次
思路:
开始思路是dp[i][k]表示第i次放砝码k。左右的质量差。后来发现这个差有多个,我们不确定哪一个是最优。那么就没有无后效性。我们再加一维
dp[i][k][w]:dp[i][k]表示第i次放砝码k。左右的质量差为w的状态是否存在。
回溯一下输出路径就可以了。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int dp[1005][15][15];
vector<int> v, ans;
int main()
{
int n, m, x;
for(int i=1; i<=10; i++){
scanf("%1d", &x);
if(x==1){
v.push_back(i);
}
}
scanf("%d", &m);
n=v.size();
if(m==1){
if(n==0){
printf("NO\n");
return 0;
}
else{
printf("YES\n");
printf("%d\n", v[0]);
return 0;
}
}
for(int i=0; i<n; i++){
dp[1][i][v[i]]=1;
}
for(int i=2; i<=m; i++){
for(int j=0; j<n; j++){
for(int k=0; k<n; k++){
for(int w=1; w<10; w++){
if(j==k){
continue;
}
if(dp[i-1][k][w]&&v[j]>w){
dp[i][j][v[j]-w]=1;
}
}
}
}
}
for(int i=0; i<n; i++){
for(int w=1; w<10; w++){
if(dp[m][i][w]){
printf("YES\n");
int s=w, u=i;
ans.push_back(v[u]);
for(int k=m-1; k>=1; k--){
for(int p=0; p<n; p++){
if(p!=u&&v[u]>s&&dp[k][p][v[u]-s]){
ans.push_back(v[p]);
s=v[u]-s;
u=p;
break;
}
}
}
for(int i=ans.size()-1; i>=0; i--){
printf("%d ", ans[i]);
}
return 0;
}
}
}
printf("NO\n");
return 0;
}