Make Bipartite dp,二分图(500)

在这里插入图片描述题意 :

  • n+1个点的无向图,点编号0-n,已知 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n) i(1in)与0之间边权值为 a i a_i ai i i i i + 1 i + 1 i+1之间边权值为 b i b_i bi n n n 1 1 1之间也有边)
  • 现在要删去一些边使图变成二分图(bipatite),问删去的边的权值和最小为多少

思路 :
在这里插入图片描述

  • 删边变成二分图,用同一种颜色代表二分图同一集合中的点,将所有点染色(两种颜色),那么需要满足同一种颜色的点之间没有边,因此删去的是同一种颜色的点之间的边
  • 题意转换为 将0-n点染成红色或蓝色,使相同颜色的点之间的边权和最小,且答案就是最小的相同颜色的点之间的边权和
  • 不失普遍性地,假设0点是红色,也就是颜色为0
  • 要计算相同颜色的点之间的边权和,显然对于每个点来说,与它本身颜色和0号点颜色以及它本身颜色和上一个点颜色有关
  • d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示当前从1号点转移到i号点,1号点的颜色是k,i号点的颜色是j的最小的同种颜色的边权和,注意这里不考虑1号点与n号点之间的边
  • 之所以状态中是“1号点的颜色”,是因为如果改为上一个点的颜色,状态转移本质是一样的;这样的话状态转移中再加一维“上一个点的颜色”就方便转移了
  • 状态转移,四重循环,i号点,i号点的颜色j,1号点的颜色k,上一个点的颜色prej,如果i号点的颜色是0,加上与0点的边,如果i号点颜色和i-1号点颜色一致,加上它们之间的边
  • 最后循环更新答案时,还要考虑是否加上n号点(当前点)与1号点之间的边
  • 时间复杂度是 O ( N ) O(N) O(N)
  • chmin函数,两个变量,第一个变量变成两者中最小值
  • 由于求的是最小,所以初始化为inf,注意dp数组的赋值初始化方法,三维,先照抄最外面的vector里面的东西,然后它再写一对圆括号,圆括号里先写上这维的大小是2,然后是再照抄着一层的vector里面的内容,同样圆括号,这一维大小是2,元素都是inf
  • 注意这题要开ll,所以干脆所有变量都ll
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <unordered_set>
#include <math.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

#define endl '\n'
#define fi first
#define se second
#define push_back
#define rep(i, l, r) for (ll i = l; i <= r; i ++ )

const ll inf = 1e18;

void chinmin(ll &a, ll b)
{
    a = min(a, b);
}

int main()
{
    cin.tie(nullptr) -> sync_with_stdio(false);
    
    ll n; cin >> n;
    vector<vector<vector<ll>>> dp(n + 1, vector<vector<ll>>(2, vector<ll>(2, inf)));
    
    vector<ll> a(n + 1);
    vector<ll> b(n + 1);
    rep(i, 1, n) cin >> a[i];
    rep(i, 1, n) cin >> b[i];
    
    dp[1][0][0] = a[1];
    dp[1][1][1] = 0;
    
    rep(i, 2, n) rep(j, 0, 1) rep(k, 0, 1) rep(prej, 0, 1)
    {
        chinmin(dp[i][j][k], dp[i - 1][prej][k] + (j == 0 ? a[i] : 0) + (j == prej ? b[i - 1] : 0));
    }
    
    ll ans = inf;
    rep(j, 0, 1) rep(k, 0, 1)
    {
        chinmin(ans, dp[n][j][k] + (j == k ? b[n] : 0));
    }
    
    cout << ans << endl;
    
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值