NBUT1480:懒惰的风纪委Elaine(多重背包)
http://ac.nbutoj.com/Problem/view.xhtml?id=1480
- 问题描述
-
Elaine是学园都市中的一个风纪委,每天都会接到命令对某个街道进行检查,并抓捕危险分子。她所在的风纪委支部附近有M条街道。这些街道由北到南并排均匀的分布在一条直线上,每条街道之间的距离都为1。但是众所周知,Elaine是一个很懒很懒的人(-..-说我坏话!!被我看到了!!),她不想一步一步走完所有街道,但好在她的好友Kuso为她制作了大量的传送卷轴。不过,因为Kuso的能力等级太低,他制作的卷轴有严重的缺点,他的卷则只能向南飞一段固定的距离(当然,他预先制作了很多种类的卷轴),而Elaine所在的风纪委支部却在最北边。每一次出去检查,Elain都要使用好几张卷轴。但如果是某些不能传送到的地方,Elaine只能走过去了。不过回来的话,她就可以用自带的传送系统传送到支部的传送点。
有一天,Elaine想知道,如果她从风纪委支部出发,可以检查那些街道。她手里有N种传送卷轴(1,2,3,,,N),每个卷轴可以传送的距离为Ai,卷轴的数量为Ci。则Elaine靠那些卷轴,可以不走路而直接传送的有哪些街道?
- 输入
-
数据有多组输入。每一组数据的第一行有两个数:N,M(0<N<=100,0<M<=1000)。分别表示传送卷轴的种类数和街道数量。在第二行有2N个数,A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000)。数据输入以0 0结束。
- 输出
-
每组数据占一行,输出一个数,为Elaine可以传送到的街道总数。
- 样例输入
-
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
- 样例输出
-
8 4
思路:将每张卷轴传送的距离看做价值,而每张卷轴又有数量限制,那么多重背包的想法自然就出来了- #include <stdio.h>
- #include <algorithm>
- #include <string.h>
- using namespace std;
- const int MAX=100000;
- const int INF = 0x7fffffff;
- int dp[MAX];
- int c[MAX],w[MAX];
- int v;
- void ZeroOnePack(int cost,int wei)//01
- {
- int i;
- for(i = v;i>=cost;i--)
- {
- dp[i] = max(dp[i],dp[i-cost]+wei);
- }
- }
- void CompletePack(int cost,int wei)//完全
- {
- int i;
- for(i = cost;i<=v;i++)
- {
- dp[i] = max(dp[i],dp[i-cost]+wei);
- }
- }
- void MultiplePack(int cost,int wei,int cnt)//多重
- {
- if(v<=cnt*cost)//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
- {
- CompletePack(cost,wei);
- return ;
- }
- else//否则就将多重背包转化为01背包
- {
- int k = 1;
- while(k<=cnt)
- {
- ZeroOnePack(k*cost,k*wei);
- cnt = cnt-k;
- k = 2*k;
- }
- ZeroOnePack(cnt*cost,cnt*wei);
- }
- }
- int main()
- {
- int n;
- while(~scanf("%d%d",&n,&v),n+v)
- {
- int i;
- for(i = 0;i<n;i++)
- scanf("%d",&c[i]);
- for(i = 0;i<n;i++)
- scanf("%d",&w[i]);
- memset(dp,0,sizeof(dp));
- for(i = 0;i<n;i++)
- {
- MultiplePack(c[i],c[i],w[i]);
- }
- int sum = 0;
- for(i = 1;i<=v;i++)
- {
- if(dp[i]==i)
- {
- sum++;
- }
- }
- printf("%d\n",sum);
- }
- return 0;
- }
POJ 1155 - TELE 树型DP(泛化背包转移)..
dp[x][y]代表以x为根的子树..连接了y个终端用户(叶子)..所能获得的最大收益...
dp[x][ ]可以看成当根为x时..有个背包空间为0~m...每个空间上记录了到到达这个空间的最大收益..
典型的泛化背包问题...
Program:
- #include<iostream>
- #include<stdio.h>
- #include<string.h>
- #include<set>
- #include<ctime>
- #include<algorithm>
- #include<queue>
- #include<cmath>
- #include<map>
- #define oo 100000007
- #define ll long long
- #define pi acos(-1.0)
- #define MAXN 3005
- using namespace std;
- struct node
- {
- int x,y,c,next;
- }line[MAXN];
- int n,m,_next[MAXN],v[MAXN],dp[MAXN][MAXN],SubNum[MAXN];
- void addline(int x,int y,int c,int m)
- {
- line[m].next=_next[x],_next[x]=m;
- line[m].x=x,line[m].y=y,line[m].c=c;
- return;
- }
- void dfs(int x)
- {
- int k=_next[x];
- SubNum[x]=dp[x][0]=0;
- if (!k) dp[x][1]=v[x],SubNum[x]=1;
- else
- while (k)
- {
- int i,j,y=line[k].y;
- dfs(y);
- SubNum[x]+=SubNum[line[k].y];
- for (i=SubNum[x];i>=1;i--)
- for (j=0;j<=SubNum[y] && j<=i;j++)
- dp[x][i]=max(dp[x][i],dp[x][i-j]+dp[y][j]+line[k].c); //泛化背包转移
- k=line[k].next;
- }
- return;
- }
- int main()
- {
- int i,num,t;
- while (~scanf("%d%d",&n,&m))
- {
- num=0;
- memset(_next,0,sizeof(_next));
- memset(dp,-0x1f,sizeof(dp));
- memset(v,0,sizeof(v));
- memset(SubNum,0,sizeof(SubNum));
- for (i=1;i<=n-m;i++)
- {
- scanf("%d",&t);
- while (t--)
- {
- int A,C;
- scanf("%d%d",&A,&C);
- addline(i,A,-C,++num);
- }
- }
- for (i=n-m+1;i<=n;i++) scanf("%d",&v[i]);
- dfs(1);
- for (i=m;i>=1;i--)
- if (dp[1][i]>=0) break;
- printf("%d\n",i);
- }
- return 0;
- }
#include<iostream> #include<stdio.h> #include<string.h> #include<set> #include<ctime> #include<algorithm> #include<queue> #include<cmath> #include<map> #define oo 100000007 #define ll long long #define pi acos(-1.0) #define MAXN 3005 using namespace std; struct node { int x,y,c,next; }line[MAXN]; int n,m,_next[MAXN],v[MAXN],dp[MAXN][MAXN],SubNum[MAXN]; void addline(int x,int y,int c,int m) { line[m].next=_next[x],_next[x]=m; line[m].x=x,line[m].y=y,line[m].c=c; return; } void dfs(int x) { int k=_next[x]; SubNum[x]=dp[x][0]=0; if (!k) dp[x][1]=v[x],SubNum[x]=1; else while (k) { int i,j,y=line[k].y; dfs(y); SubNum[x]+=SubNum[line[k].y]; for (i=SubNum[x];i>=1;i--) for (j=0;j<=SubNum[y] && j<=i;j++) dp[x][i]=max(dp[x][i],dp[x][i-j]+dp[y][j]+line[k].c); //泛化背包转移 k=line[k].next; } return; } int main() { int i,num,t; while (~scanf("%d%d",&n,&m)) { num=0; memset(_next,0,sizeof(_next)); memset(dp,-0x1f,sizeof(dp)); memset(v,0,sizeof(v)); memset(SubNum,0,sizeof(SubNum)); for (i=1;i<=n-m;i++) { scanf("%d",&t); while (t--) { int A,C; scanf("%d%d",&A,&C); addline(i,A,-C,++num); } } for (i=n-m+1;i<=n;i++) scanf("%d",&v[i]); dfs(1); for (i=m;i>=1;i--) if (dp[1][i]>=0) break; printf("%d\n",i); } return 0; }