题意:往天平两边按照左右左右的顺序放置砝码,往左放了砝码后,左边需要比右边重,往右边放置砝码后,右边需要比左边重,给出现有的砝码种类数量不限,求一个放置的解。
方法:dp,令dp[i][j][k]表示,第k个放置重量为i,比对面重了j,那么他就可以被
dp[t][i-j][k-1]转移到,即当前放i重了j,那么上一个一定比上上一个重了i-j,枚举t即可。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
char ch = getchar(); int x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int dp[20][20][1005];//fang k duo j di i
char s[200];
int cnt[200];
int m;
vector<int >vec;
void findpath(int nowwei,int dis,int dep)
{
if (dep == 0)return;
vec.push_back(nowwei);
upd(i, 1, 10)
{
if (dp[i][nowwei - dis][dep - 1]&&i!=nowwei) {
findpath(i, nowwei - dis, dep - 1); return;
}
}
}
int main()
{
cin >> s;
m = read();
up(i, 0, 10)if (s[i] == '1')cnt[i + 1] = 1;
upd(i, 1, 10)if(cnt[i])dp[i][i][1] = 1;
upd(i, 2, m)
{
upd(j, 1, 10)
{
upd(k, 1, 10)
{
if (!cnt[k])continue;
if (k <= j)continue;
upd(p, 1, 10)
{
if(cnt[p]&&p!=k)
dp[k][j][i] |= dp[p][k - j][i-1];
}
}
}
}
upd(j, 1, 10)upd(k, 1, 10)if (dp[j][k][m]) {
findpath(j, k, m); goto ed;
}
ed: if (vec.size() == 0) { cout << "NO" << endl; return 0; }
cout << "YES" << endl;
reverse(vec.begin(), vec.end());
for (auto k : vec)cout << k << " ";
return 0;
}
说实话没太明白网上暴力dfs的复杂度,就算剪了支感觉也很慢啊。