题意:100组数据,给出m~40和s~300, 再给出m种电子硬币,每种硬币有两种金额xi,yi。现在要在m种硬币种选若干个硬币,可以重复选同一种硬币, 使得(x1 + x2 + .... + xn) ^ 2 + (y1 + y2 + ... + yn) ^ 2 == s * s, 要求n尽量小,(n为选取硬币的个数), 如果不能选出满足条件的硬币,输出-1。
题解:很简单,就是dp【i】【j】就好,每次都有可能达到s*s,都要更新下ans
重点:二维完全背包
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 300 + 10;
const int INF = INT_MAX/2 - 1;
int dp[maxn][maxn], s, n;
int ans;
struct info
{
int x, y;
};
info ren[maxn];
void getDp()
{
ans = INF;
memset(dp, -1, sizeof(dp));//不能达到
dp[0][0] = 0;//初始化
for(int i = 1;i <= n;i++)
{
for(int a = ren[i].x;a <= s;a++)//二维背包从小到大
{
for(int b = ren[i].y;b <= s;b++)//也是从小到大
{
if(dp[a-ren[i].x][b-ren[i].y]!=-1&&( dp[a][b]==-1|| (dp[a-ren[i].x][b-ren[i].y]+1<dp[a][b]) ) )//可以更新dp【a】【b】
{
dp[a][b] = dp[a-ren[i].x][b-ren[i].y]+1;
if(a*a + b*b == s*s)//直接统计就好
{
ans = min(ans, dp[a][b]);
}
}
}
}
}
}
void solve()
{
getDp();
if(ans != INF)
printf("%d", ans);
else
{
printf("not possible");
}
printf("\n");
}
int main()
{
// freopen("3Cin.txt", "r", stdin);
//freopen("3Cout.txt", "w", stdout);
int ncase;
scanf("%d", &ncase);
while(ncase--)
{
scanf("%d%d", &n, &s);
REP_D(i, 1, n)
{
scanf("%d%d", &ren[i].x, &ren[i].y);
}
solve();
}
return 0;
}