zjut1698Coins

/*
多重背包
zjut 1698 Coins 
思路:
根据每个coin的x y值大致得出每种coin最多可取几个,然后用二进制处理产生新的coin,将问题转化为01背包
状态转移:dp[j][k]=min(dp[j-xx[i]][k-yy[i]]+cost[i],dp[j][k]);
*/
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int m,s;
int x[101],y[101],dp[301][301],vis[301][301];
int xx[100001],yy[100001],cost[100001];
const int INF=100000;
int main()
{
	int cas;
	cin>>cas;
	while(cas--)
	{
		cin>>m>>s;
		for(int i=0;i<m;i++)
            cin>>x[i]>>y[i];
        memset(vis,0,sizeof(vis));
	    memset(cost,0,sizeof(cost));
		int num=0;
		for(int i=0;i<m;i++)
		{
			int ci=pow((s*s)/(x[i]*x[i]+y[i]*y[i])*1.0,0.5);
			int k=1;
            for(;;)
			{
				if(k>ci)break;
				xx[num]=x[i]*k,yy[num]=y[i]*k;
				vis[x[i]*k][y[i]*k]=1;
				cost[num++]=k;
				ci-=k;
				k=k<<1;
				
			}
			if(ci&&!vis[x[i]*ci][y[i]*ci])
			{
				xx[num]=x[i]*ci,yy[num]=y[i]*ci;cost[num++]=ci;vis[x[i]*ci][y[i]*ci]=1;
			}
		}
		
        for(int i=0;i<=s;i++)
			for(int j=0;j<=s;j++)
				dp[i][j]=INF; 
         

      for(int i=0;i<num;i++)
	  {
		  dp[xx[i]][yy[i]]=cost[i];
	  }
	     
		for(int i=0;i<num;i++)
		{
			for(int j=xx[i];j<=s;j++)
                for(int k=yy[i];k<=s;k++)
				{
				    if(j*j+k*k<=s*s)
					{
						dp[j][k]=min(dp[j-xx[i]][k-yy[i]]+cost[i],dp[j][k]);
					}
				}
		}
       
		int ans=INF;
		for(int i=0;i<=s;i++)
			for(int j=0;j<=s;j++)
				if(i*i+j*j==s*s)
				{
					ans=min(ans,dp[i][j]);
				}

				if(ans==INF) cout<<"not possible"<<endl;
				else cout<<ans<<endl;
	}
}
http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1698
posted on 2011-05-11 23:02  4.5.6  阅读(136)  评论(0编辑  收藏  举报