uva 10306 - e-Coins(完全双肩包)

uva 10306 - e-Coins(完全背包)

题目链接:10306 - e-Coins


题目大意:给出m和s, 再给出m种电子硬币,每种硬币有两种金额xi,yi。现在要在m种硬币种选若干个硬币,可以重复选同一种硬币, 使得(x1 + x2 + .... + xn) ^ 2 + (y1 + y2 + ... + yn) ^ 2 == s * s, 要求n尽量小,(n为选取硬币的个数), 如果不能选出满足条件的硬币,输出-1。


解题思路:二维的完全背包问题,注意要用long long。


#include <stdio.h>
#include <string.h>
const int N = 305;

struct coin{
    int x;
    int y;
}val[50];
int n, s, S, dp[N][N];

void read() {
   memset(val, 0, sizeof(val));
   scanf("%d%d", &n, &s);
   S = s * s;
   for (int i = 0; i < n; i++)
       scanf("%d%d", &val[i].x, &val[i].y);
}

int solve() {
    int cnt = 1 << 30;
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1;
    for (int k = 0; k < n; k++) {
	for (int i = 0; i <= s; i++) {
	    for (int j = 0; j <= s; j++) {
		if (dp[i][j]) {
		    int p = i + val[k].x, q = j + val[k].y;
		    if (p > s || q > s) break;
		    if (dp[p][q] == 0 || dp[i][j] + 1 < dp[p][q])
			dp[p][q] = dp[i][j] + 1;
		    if (p * p + q * q == S && dp[p][q] < cnt)
			cnt = dp[p][q];
		}
	    }
	}
    }
    if (cnt == 1 << 30) return 0;
    else return cnt;
}

int main() {
    int cas;
    scanf("%d", &cas);
    while (cas--) {
	read();
	int ans = solve();
	if (ans)
	    printf("%d\n", ans - 1);
	else
	    printf("not possible\n");
    }
    return 0;
}