Codeforces Round #383 (Div. 2)D-(並查集&分組揹包)|(搜尋&01揹包)
阿新 • • 發佈:2018-12-23
傳送門
分組揹包模板題。
用並查集搞一搞一齊的關係就好。
然後就是分組揹包的模板了,注意,在分組的時候,把i組所有和加起來 這一個虛擬的物品分到 i組裡,而不能獨立分組,不然會造成某一個模特的的多次使用。。
或者用搜索,這個搜尋用滾動陣列的時候,類似於樹形dp裡面,在一個樹內進行01揹包。
但是在遍歷的時候,可能會出現從0陣列 轉到0陣列的情況(1陣列先前已經被vis掉了,如果我們不處理這個結果就會發生前面的結果可能沒有辦法繼承。)所以我們每次可以 把所有的陣列 都給賦值了。
這個很重要,本菜沒有想到好的方法。大家可以一起交流
dfs搜尋版本
#include <bits/stdc++.h>
#define MOD 1000000007
#define maxn 100005
using namespace std;
typedef long long ll;
int dp[2][1005], vis[1005];
int w[1005], b[1005], h, sum1, sum2;
vector<int> v[1005];
int n, m, ww, a, bb;
void dfs(int k,int j){
for(int i = ww; i >= w[k]; i--){
dp[j%2][i] = max(dp[(j-1)%2][i-w[k]] + b[k], dp[j%2 ][i]);
}
vis[k] = 1;
sum1 += w[k];
sum2 += b[k];
for(int i = 0; i < v[k].size(); i++){
if(vis[v[k][i]] == 0){
dfs(v[k][i],j);
}
}
}
int main(){
// freopen("in.txt", "r", stdin);
scanf("%d%d%d", &n, &m, &ww);
for(int i = 1; i <= n; i++)
scanf ("%d", w+i);
for(int j = 1; j <= n; j++)
scanf("%d", b+j);
for(int i = 1; i <= m; i++){
scanf("%d%d",&a,&bb);
v[a].push_back(bb);
v[bb].push_back(a);//建圖,然後用搜索的方法處理,類似樹形dp
}
for(int i=1;i<=n;i++){
sum1=0;sum2=0;
//memset(vis,false,sizeof(vis));
if(!vis[i])
dfs(i,i);//一層一層的揹包。
for(int j = ww; j >= sum1; j--){
dp[i%2][j] = max(dp[(i-1)%2][j-sum1] + sum2, dp[i%2][j]);
}
for(int x=1;x<=ww;x++)
dp[(i+1)%2][x]=dp[i%2][x];
// cout<<endl;
}
printf("%d\n",dp[n%2][ww]);
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
/*分組揹包,模板題。
*/
const int maxn=100005;
int fa[maxn];
void init(int m){
for(int i=0;i<maxn;i++)
fa[i]=i;
}
int find1(int a){
if(fa[a]==a)return a;
return fa[a]=find1(fa[a]);
}
void unite(int a,int b ){
int x=find1(a);
int y=find1(b);
if(x==y)return;
fa[x]=y;
}
int c[maxn];
int v[maxn];
vector<int>G[maxn];
int dp[maxn];
int main()
{ int m,n,p;
int a,b;
scanf("%d%d%d",&m,&n,&p);
init(m*2);
for(int i=1;i<=m;i++){
scanf("%d",&c[i]);
}
for(int i=1;i<=m;i++){
scanf("%d",&v[i]);
}
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
unite(a,b);
}
int t=m;
for(int i=1;i<=m;i++)
G[find1(i)].push_back(i);//根據ufs關係來確定一個圖圖
for(int i=1;i<=m;i++){
int sum1=0;
int sum2=0;
if(!G[i].size()) continue;
for(int j=0;j<G[i].size();j++){
sum1+=c[G[i][j]];
sum2+=v[G[i][j]];
}
if(G[i].size()<=1) continue;
c[1+t]=sum1;
v[++t]=sum2;
G[i].push_back(t);
}
/*for(int i=0;i<=t;i++){
cout<<i<<"@@";
for(int j=0;j<G[i].size();j++)
printf("%d ",G[i][j]);
cout<<endl;
}*/
//cout<<m<<endl;
for(int i=1;i<=t;i++){
if(!G[i].size()) continue;
for(int j=p;j>=0;j--){
for(int k=0;k<G[i].size();k++)
if(j>=c[G[i][k]])
dp[j]=max(dp[j],dp[j-c[G[i][k]]]+v[G[i][k]]);
}
}
printf("%d\n",dp[p]);
return 0;
}