F - Make Bipartite
题目描述
给出 n + 1 n+1 n+1个点,下标是 0 0 0到 n n n,从 1 1 1到 n n n都存在一体指向0的带权无向边,边权为ar[i],同时从 i i i到 i + 1 i+1 i+1也存在一条带权无向边,边权为 b r [ i ] br[i] br[i],当然,n指向的不是n+1,是1,即是一个环
问你形成二分图最小需要删除的边的权值之和是多少
思路
要形成二分图,点i可以和 i − 1 i-1 i−1连边,也可以跟 0 0 0连边
假设最后形成的二分图进行染色后
如果 i i i跟 i − 1 i-1 i−1 的颜色相同,说明要删除 b r [ i − 1 ] br[i-1] br[i−1]边
如果 i i i跟 0 0 0的颜色相同,说明要删除 a r [ i ] ar[i] ar[i]边
那我们假设 0 0 0的颜色是0
设 d p dp dp的状态为:
d p [ i ] [ j ] [ k ] 表示第 i 个点的颜色为 j ,第一个点的颜色为 k dp[i][j][k]表示第i个点的颜色为j,第一个点的颜色为k dp[i][j][k]表示第i个点的颜色为j,第一个点的颜色为k
我们可以通过枚举当前点的颜色和上一个点的颜色来进行状态转移文章来源:https://www.toymoban.com/news/detail-519803.html
最后不要忘了计算一下n和1的颜色文章来源地址https://www.toymoban.com/news/detail-519803.html
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
typedef long long ll;
ll mod = 998244353;
#define MAX 1000050
ll n, m, k, x, y, z;
ll ar[MAX], br[MAX];
ll dp[MAX][2][2];
ll min(ll x, ll y){
return x < y ? x : y;
}
int main(){
scanf("%lld", &n);
for(int i = 1; i <= n; ++i)scanf("%lld", &ar[i]);
for(int i = 1; i <= n; ++i)scanf("%lld", &br[i]);
memset(dp, 0x3f, sizeof(dp));
dp[1][0][0] = ar[1];dp[1][1][1] = 0;
for(int i = 2; i <= n; ++i){
for(int j = 0; j < 2; ++j){
for(int pre = 0; pre < 2; ++pre){
for(int k = 0; k < 2; ++k){
dp[i][j][k] = min(dp[i][j][k],dp[i-1][pre][k] +(j == 0 ? ar[i] : 0) +(pre == j ? br[i-1] : 0));
}
}
}
}
ll ans = 1e18;
for(int j = 0; j < 2; ++j){
for(int k = 0; k < 2; ++k){
ans = min(ans, dp[n][j][k] + (j==k?br[n]:0));
}
}
printf("%lld\n", ans);
return 0;
}
到了这里,关于AtCoder Beginner Contest 229 「F dp」的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!