西安邀请赛-D(带权并查集+背包)
题目链接:https://nanti.jisuanke.com/t/39271
题意:给定n个物品,m组限制,每个物品有个伤害值,现在让两个人取完所有物品,要使得两个人取得物品伤害值之和最接近,输出伤害值不小于另一个的人的伤害值,每组限制包括两次数x y,表示物品x和物品y不能由同一个人取得。
思路:思路是通过bfs或并查集将有关系的物品合并为一个物品,合并的物品有两个值,每个人必须分别取每个物品的一个值,然后就是背包问题了。
具体实现就是用root[i]表示i的祖先,a[i]表示i与其祖先的关系(为0表示和祖先放在一边,为1表示和祖先不能放一边),可以得到(x->z=(x->y)^(y->z),x->z表示物品x,z的关系,还有x->y=y->x),然后就可以通过并查集来维护所有限制关系。之后遍历所有祖先等于自己的个数,即合并后的连通块个数,设为k。然后把第i个集合中和与祖先关系为0的都加在b[i][0]上,把第i个集合中和祖先关系为1的都加在b[i][1]上。然后还有个操作就是因为每个人分别取b[i][0],b[i][1]中的一个,要使差值最小,那么可以将b[i][0],b[i][1]同时减一个数使得min(b[i][0],b[i][1])=0,这并不影响答案。这样就是减去min(b[i][0],b[i][1])=0,剩下那个非0的数存进d[i]中,并且将所有d[i]加起来得到sum1。
那么问题就转换为有k个物体,价值为d[i],这里价值和体积一样,在空间为sum/2的背包中,每次有选或不选两种可能,求背包最大的价值为多少。然后就可以得到结果了。说的有点绕,但思路不复杂,理解一下自己写写,代码写得有点乱,不建议看。。
AC代码:
#include<cstdio>
#include<map>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; int T,n,m,sum1,sum2,sum3,sum4,c[],root[],a[];
int b[][],d[],dp[]; int getr(int k){
if(root[k]==k) return k;
else{
int tmp=root[k];
root[k]=getr(root[k]);
a[k]^=a[tmp];
return root[k];
}
} int main(){
scanf("%d",&T);
while(T--){
memset(b,,sizeof(b));
memset(d,,sizeof(d));
memset(dp,,sizeof(dp));
sum1=,sum2=,sum3=;
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
root[i]=i,a[i]=;
for(int i=;i<=n;++i)
scanf("%d",&c[i]),c[i]/=,sum1+=c[i];
while(m--){
int x,y,rx,ry;
scanf("%d%d",&x,&y);
rx=getr(x),ry=getr(y);
if(rx==ry) continue;
root[ry]=rx;
a[ry]=^a[y]^a[x];
}
map<int,int> mp;
int k=;
for(int i=;i<=n;++i)
if(getr(i)==i)
mp[i]=++k;
for(int i=;i<=n;++i){
int r=getr(i);
b[mp[r]][a[i]]+=c[i];
}
for(int i=;i<=k;++i)
d[i]=abs(b[i][]-b[i][]),sum2+=d[i],sum3+=min(b[i][],b[i][]);
sum4=sum2/;
for(int i=;i<=k;++i)
for(int j=sum4;j>=d[i];--j)
dp[j]=max(dp[j],dp[j-d[i]]+d[i]);
printf("%d\n",(sum1-(sum3+dp[sum4]))*);
}
return ;
}
西安邀请赛-D(带权并查集+背包)的更多相关文章
- poj1417 带权并查集 + 背包 + 记录路径
True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2713 Accepted: 868 Descrip ...
- poj1417(带权并查集+背包DP+路径回溯)
题目链接:http://poj.org/problem;jsessionid=8C1721AF1C7E94E125535692CDB6216C?id=1417 题意:有p1个天使,p2个恶魔,天使只说 ...
- POJ 1703 Find them, Catch them(带权并查集)
传送门 Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 42463 Accep ...
- [NOIP摸你赛]Hzwer的陨石(带权并查集)
题目描述: 经过不懈的努力,Hzwer召唤了很多陨石.已知Hzwer的地图上共有n个区域,且一开始的时候第i个陨石掉在了第i个区域.有电力喷射背包的ndsf很自豪,他认为搬陨石很容易,所以他将一些区域 ...
- poj1984 带权并查集(向量处理)
Navigation Nightmare Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 5939 Accepted: 2 ...
- 【BZOJ-4690】Never Wait For Weights 带权并查集
4690: Never Wait for Weights Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 88 Solved: 41[Submit][ ...
- hdu3038(带权并查集)
题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=3038 题意: n表示有一个长度为n的数组, 接下来有m行形如x, y, d的输入, 表示 ...
- 洛谷OJ P1196 银河英雄传说(带权并查集)
题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山 ...
- poj1984 带权并查集
题意:有多个点,在平面上位于坐标点上,给出一些关系,表示某个点在某个点的正东/西/南/北方向多少距离,然后给出一系列询问,表示在第几个关系给出后询问某两点的曼哈顿距离,或者未知则输出-1. 只要在元素 ...
随机推荐
- PSFTP使用简单教程
psftp是putty工具下的一个sftp工具.SFTP(Secure File Transfer Protocol)安全文件传输协议,SFTP是SSH的一部分,是一种传输档案至 Blogger 伺服 ...
- 交换机配置——VTP管理交换机的VLAN配置
一.实验目的:将S1配置成VTP-Server,S2配置成VTP-Transparent,S3配置成VTP-Client,S4配置成VTP-Client 二.拓扑图如下 三.具体步骤: (1)S1交换 ...
- Spring——注解
一.IOC注解 1.用于向Spring容器中注入bean: @Component:向Spring容器中注入bean @Repository:用于标注Dao层 @Service:用于标注Service业 ...
- 筛选前十按a-z顺序排
需求: 从arr数组中筛选出num最多的前十个,若是最后几个num的值一样,则最后几个按字母a-z的顺序排序,最后取出num最大的前十个: var arr = [{"id":&qu ...
- JavaWeb_(Struts2框架)Log4j的配置以及解决中文乱码
此系列博文基于同一个项目已上传至github 传送门 JavaWeb_(Struts2框架)Struts创建Action的三种方式 传送门 JavaWeb_(Struts2框架)struts.xml核 ...
- C++入门经典-例6.21-比较string字符串,比较两个字符串
1:使用“>”.“!=”.“>=”等比较运算符可以比较两个字符串的内容.比较的方法是将两个string字符串从头开始比较每一个字符,直到出现两者不一致.比较这两个不相同的字符的字面值,得出 ...
- cha[] strrev(char[])
反转字符串 保留在原函数中
- PHP 分页+查询
首先是主页面,与上篇分页页面相同 <table width="100%" border="1" cellpadding="0" cel ...
- 堆排序 java
<pre name="code" class="java">package heapSort; /** * 大根堆 * @author root * ...
- LC 413. Arithmetic Slices
A sequence of number is called arithmetic if it consists of at least three elements and if the diffe ...