其他分享
首页 > 其他分享> > 洛谷 P1455 搭配购买

洛谷 P1455 搭配购买

作者:互联网

搭配购买这一题很适合刚学并查集的同学练习。

这一题思路是:并查集 01背包

  并查集:将搭配购买的云用并查集来连接, 并将连接起来的一坨云看做一个物品,再用01背包思路,就可以解决喽。

个人认为的难点是:如何用并查集和怎样存储云的价值和价钱,还有怎么将云的价值和云的价钱合并。

    我个人是这样解决的:

      用结构体定义 p -- 表示并查集的下标,vl -- 价值,r -- 价钱

    

typedef struct bcj1 {
    int p,vl,r;
}BCJ;
BCJ bcj[N];

    那么查找和路径压缩就是

int find(int x) {
  if(bcj[x].p != x) bcj[x].p = find(bcj[x].p);
  return bcj[x].p;        
}

    完成并查集后,

    就是将一坨云的价值和价格存入,转换为01背包问题

    这里我用的是pair<int,int>,first表示价格,second表示价值,

    rep(i,1,n) { // 等价于 for(int i = 1; i <= n; ++i)
        int k = find(i);
        kn[k].first += bcj[i].r;
        kn[k].second += bcj[i].vl;
    }
    sort(kn+1, kn+n+1, cmp); // cmp 自己写的,排序由大到小
    rep(i, 1, n) {
        if(kn[i].first == 0 && kn[i].second == 0) { // 去掉没有 价值的数值
            break;
        }
        cnt++;
    }

    最后是01背包

    for(int i = 1; i <= cnt; ++i) {
        for(int j = w; j >= kn[i].first; --j) {
            dp[j] = max(dp[j], dp[j - kn[i].first] + kn[i].second);
        }
    }
    cout<<dp[w];

    输出答案 dp[w]

最后贴个AC代码:

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stdio.h>
#include <sstream>
#include <algorithm>
using namespace std;

#define rep(i,x,n) for(int i = x; i <= n; i++)

typedef long long LL;
typedef pair<int,int> PII;
typedef struct bcj1 {
    int p,vl,r;
}BCJ;

const int N = 10021;
int dp[N];
BCJ bcj[N];
PII kn[N];
int find(int x) {
    if(bcj[x].p != x) bcj[x].p = find(bcj[x].p);
    return bcj[x].p; 
}
bool cmp(PII a, PII b) {
    if(a.first == b.first) {
        return a.second > b.second;
    } else {
        return a.first > b.first;
    }
}
void test();

int main()
{
    //test();
    int n, m, w;
    cin>>n>>m>>w;
    rep(i,1,n) bcj[i].p = i;
    rep(i,1,n) {
        int c,d;
        cin>>c>>d;
        bcj[i].r = c; bcj[i].vl = d;
    }
    rep(i,1,m) {
        int v1,v2;
        cin>>v1>>v2;
        bcj[find(v1)].p = find(v2);
    }
    int cnt = 0;
    rep(i,1,n) {
        int k = find(i);
        kn[k].first += bcj[i].r;
        kn[k].second += bcj[i].vl;
    }
    sort(kn+1, kn+n+1, cmp);
    rep(i, 1, n) {
        if(kn[i].first == 0 && kn[i].second == 0) {
            break;
        }
        cnt++;
    }
    for(int i = 1; i <= cnt; ++i) {
        for(int j = w; j >= kn[i].first; --j) {
            dp[j] = max(dp[j], dp[j - kn[i].first] + kn[i].second);
        }
    }
    cout<<dp[w];
    return 0;
}


void test() {
    #define mytest
    #ifdef mytest
    freopen("test.out", "w", stdout);
    #endif
}
View Code

 

标签:P1455,洛谷,bcj,搭配,kn,int,include,dp,first
来源: https://www.cnblogs.com/yahh/p/16536801.html