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;
}