dp 0-1背包+并查集 CodeForce 742D
http://codeforces.com/problemset/problem/742/D
动态规划专题训练
题目大意:选几个美丽的小姐来参加舞会,但是每位小姐都是有着体重和魅力值,要求在有总体重上限w的情况下尽可能的选出总魅力值最高的小姐来参加。
当然如果是这样就可以直接套0-1背包的模板了。然而还加上了一个限制,就是每一位小姐都会和其他的小姐之间有个友谊关系,在有友谊关系的情况下,要么只选一个人,要么全部都请过去。
思路:
先用并查集解决友谊圈的问题,找出同是一个友谊圈的小姐,并放在一块。
接着利用0-1背包的思路,来解决。
状态转移方程 dp(s)=max{dp(s-w(k))+b(k)};//k是在一个圈里的小姐
然后在进行一次判断就是这个跟这个圈的小姐全部都选上的方案相比怎么样
dp(s)=max{dp(s-wl)+bl};
做的时候小心点就好了,今天唯一一次AC
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int d[1006];
int v[1006];
int a[1006],b[1006];
vector<int> h[1006];
int al[1006],bl[1006];
int find(int s)
{
return s==v[s]?s:v[s]=find(v[s]);
}
int n,m,w;
void read()
{
scanf("%d %d %d",&n,&m,&w);
for(int i = 0; i <= n; i++ )
v[i]=i;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++)
{
scanf("%d", &b[i]);
}
for(int i = 0; i < m; i++)
{
int u,vi;
scanf("%d %d",&u, &vi);
int x = find(u);
int y = find(vi);
v[x]=y;
}
}
int main()
{
memset(d, 0, sizeof(d));
memset(al, 0 ,sizeof(al));
memset(bl, 0, sizeof(bl));
read();
for(int i = 1; i <= n; i++)
{
h[find(i)].push_back(i);
al[find(i)] += a[i];
bl[find(i)] += b[i];
}
for(int i = 1; i <= n; i++)
{
if(h[i].empty()) continue;
for(int j = w; j >= 0; j--)
{
for(int k = 0; k < h[i].size(); k++)
{
if(j - a[h[i][k]] >= 0)
d[j]=max(d[j - a[h[i][k]]] +b[h[i][k]],d[j]);
}
if(j - al[i] >= 0) d[j]=max(d[j - al[i]]+bl[i], d[j]);
}
}
int ans=-1;
for(int i = 0; i <= w; i++ ) ans=max(ans, d[i]);
printf("%d\n",ans);
return 0;
}