Problem D: 欠债还钱 (多重背包)

Description
llk经常和wy一起去yh小饭馆吃盖浇饭,一天他们吃完后llk把两个人的钱一起付了,但是wy不想欠llk的钱。现在wy手中有一些散钱,llk手中也有一些散钱,wy想知道能不能刚好使得两不相欠,但是wy很笨,你能帮助wy吗?

Input
多组测试数据,每组第一行输入3个非负整数,C,n,m。C代表wy欠llk的钱,n代表wy手中钱面值的种类,m代表llk手中钱面值的种类。接下来的n行,每行两个数v, c,分别代表wy手中面值为v的钱币有c个。再接下来的m行,每行两个数v,c,分别代表llk手中面值为v的钱币有c个。 (C <= 10000; 1<=n, m<50; 0<=v < =100; 0<=c<=10 )

Output
每组数据输出一行,如果存在一种方案使得wy和llk两不相欠,输出YES,否则输出NO。

Sample Input
7 1 1
10 1
1 10
Sample Output
YES
HINT
wy给了llk一张10元的,llk又给了wy三个1元的

思路:刚开始想用dfs做的,但是太难写了。赛后讨论是个多重背包。考的是dp判定性。

状态定义:dp[i][j]表示前i个种类还钱数为j时候 的合法情况。

状态转移:dp[i][j]=dp[i-1][j-k*v[i]] (k:0~c[i])

和平时的dp有点不一样的是初始赋值1之后然后dp[i][j]为1的就不用转移了。并且要注意转移的条件是j-k*v[i]>=0(要还钱数为正)和j-k*v[i]<=C,我的输入这样做防止越界;

然后具体看代码注释,学校的oj容易Tle


 

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=150;
typedef int  LL;//要int,不然T 
LL dp[maxn][10010];
LL v[maxn];
LL c[maxn];
int main(void)
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	LL C,n,m;
	while(cin>>C>>n>>m)
	{
		memset(dp,0,sizeof(dp));
		for(LL i=1;i<=n;i++)
			 cin>>v[i]>>c[i];
		for(LL i=n+1;i<=n+m;i++)
			{
				cin>>v[i]>>c[i];
				v[i]=-v[i];	
			}	 
		dp[0][0]=1;
		for(LL i=1;i<=n+m;i++)
			for(LL j=0;j<=C;j++)//如果硬要j<=10000,把j和k的循环换一下,不然就T了 
				for(LL k=0;k<=c[i];k++)/// 
				{
					if(dp[i][j]) continue;//已经是1的别更新了 
					if(j-k*v[i]>=0&&j-k*v[i]<=C)//v[i]会是个负数,<=C,不然可能超内存 
					dp[i][j]=dp[i-1][j-k*v[i]];
				}
		if(dp[n+m][C]) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;	
	}
return 0;
}

上面的码有点问题..但是Oj的数据比较emmm居然过了.问了几个人说背包优化后T了没优化没有T,几个人交流了一下数据可能有问题.修正代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
typedef long long ll;
using namespace std;
const   int N=110;
int dp[N][50010];
int v[N];
int c[N];
int main()
{
    int C,n,m;
    while(scanf("%d%d%d",&C,&n,&m)!=EOF)
    {
        for(int i=1;i<=n+m;i++)
        for(int j=0;j<50010;j++)
        dp[i][j]=0;
        int sum=C;
        for(int i=1;i<=n;i++)
        {
		scanf("%d%d",&v[i],&c[i]);
		sum+=v[i]*c[i];
		}
        for(int i=n+1;i<=n+m;i++)
        {
        scanf("%d%d",&v[i],&c[i]);
        v[i]=-v[i];
        }
        dp[0][0]=1;
        for(int i=1;i<=n+m;i++)
        for(int k=0;k<=sum;k++)
        for(int j=0;j<=c[i];j++)
        {
        	if(dp[i][k])	break;
        	if(k-j*v[i]>=0&&dp[i-1][k-j*v[i]])
        	{
        //		cout<<i<<' '<<k<<endl;
			dp[i][k]=dp[i-1][k-j*v[i]];}
		}
        if(dp[n+m][C])  printf("YES\n");
        else        printf("NO\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/106580246
今日推荐