您的位置:首页 > 其它

poj 1742 多重背包变种 对时间要求特别严格

2013-09-05 18:24 176 查看
1 多重背包物品二进制拆分后01背包
#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

#define MAX_V (100+1)
#define MAX_F (100000+1)

int A[MAX_V],C[MAX_V];
int Value[MAX_F];
bool F[MAX_F];

int n,m;
#define printf //
int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
if(n==0 && m== 0)
return 0;

for(int i=1;i<=n;i++)
{

scanf("%d",&A[i]);
//cin>>A[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&C[i]);
//cin>>C[i];
}

int cnt = 0;
//binary拆分物品
//C数量 A价值
for(int i=1;i<=n;i++)
{
printf("old:数量:%d 价值:%d\n",C[i],A[i]);
int tc = C[i];
for(int k=1;k<=tc; k <<= 1)
{
Value[cnt++] = A[i] *k;
tc -= k;
printf("\t\t %d:价值:%d \n",k,k*A[i]);

}

if(tc > 0)
{
Value[cnt++] = A[i] * tc;
printf("\t\t%d:价值:%d\n",C[i],C[i]*A[i]);
}
}

memset(F,0,sizeof(F));
F[0]=true;
for(int i=0;i<cnt;i++)
{
//for(int v=m;v>Value[i];v--)
for(int v=m;v>=Value[i];v--)
{
if(F[v])
continue;
if(F[v-Value[i]])
F[v] = true;
//F[v] = F[v] || F[v-Value[i]];

printf("i=%d(%d) F[v-x]=%d F[%d]=%d\n",i,Value[i],F[v-Value[i]],v,F[v]);
//				if(F[v - Value[i] ] + value[i] > F[v])
//					F[v] = F[v - value[i] ] + value[i];
}
}

int sums = 0;
for(int v=m;v>0;v--)
if(F[v])
{
++sums;
}

cout<<sums<<endl;

}
}



2 按照之前网上说的思路尝试优化,但依然不理想,依然TLE.

#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

#define MAX_V (100+1)
#define MAX_F (100000+1)

int A[MAX_V],C[MAX_V];
int Value[MAX_F];
bool F[MAX_F]; //F[v]为使用i能否达到v

int n,m;
#define printf //
int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
if(n==0 && m== 0)
return 0;

for(int i=1;i<=n;i++)
{

scanf("%d",&A[i]);
//cin>>A[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&C[i]);
//cin>>C[i];
}

memset(F,0,sizeof(F));
F[0]=true;
int maxv = 0;
int sum = 0;
for(int i=1;i<=n;i++)
{
for(int v=maxv;v>=0;v--)
{
if(F[v])
{
for(int k=1;k<= C[i];k++)
{
int ki = v+ k*A[i];
if(ki >m )
break;
if(F[ki])
continue;
++sum;
F[ki]= true;

if(ki > maxv)
maxv = ki;
}

}

}
}

//		int sums = 0;
//		for(int v=m;v>0;v--)
//		{
//			printf("%d=%d\n",v,F[v]);
//			if(F[v])
//			{
//				++sums;
//			}
//		}

cout<<sum<<endl;

}
}


3 参考

/article/10277896.html

混合 完全背包和01背包优化解决多重背包问题

如果一个物品的value*amount >= m时,则认为此物品可以取任意多件,因为在物品的件数限制amount内,一定可以满足m了。

#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

#define MAX_V (100+1)
#define MAX_F (100000+1)

int A[MAX_V],C[MAX_V];
bool F[MAX_F];

int n,m;
#define printf //
void ZeroOnePack(int value)
{
printf("zero one pack value:%d\n",value);
for(int v=m;v>=value;--v)
{
F[v] |= F[v-value];
printf("F[%d] = %d\n",v,F[v]);
}
}
void CompletePack(int value)
{
for(int v=value;v<=m;v++) //完全背包和01背包只有循环顺序不同,具体可参考背包问题九讲
F[v] |= F[v-value];
}
void MultiPack(int value,int amount)
{

if(value * amount >= m)
{

CompletePack(value);
return;
} //这段对某些可以应用完全背包的物品,进行完全背包才最终AC的。
int k=1;
while(k<amount)
{
ZeroOnePack(value * k);
amount -= k;
k <<= 1;
}
if(amount)
ZeroOnePack(value*amount);
}

int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
if(n==0 && m== 0)
return 0;

for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&C[i]);
}

memset(F,0,sizeof(F));
F[0] = true;
//数量c
for(int i=1;i<=n;i++)
{
if(C[i])
{
MultiPack(A[i],C[i]);
}
}

int sums = 0;
for(int v=m;v>0;v--)
if(F[v])
{
++sums;
}

cout<<sums<<endl;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: