luogu3872 [TJOI2010]电影迷

网友投稿 587 2022-10-05

luogu3872 [TJOI2010]电影迷

luogu3872 [TJOI2010]电影迷

(​​ 题目描述

小A是一个电影迷,他收集了上百部的电影,打算从中挑出若干部在假期看完。他根据自己的口味和网上的介绍,对每部电影X都打了一个分数vX,表示自己喜欢的程度。这个分数的范围在-1000至1000之间,越大表示越喜欢。小A每看一部电影X,他的体验值就会加上vX。

另外,因为某些电影是组成一个系列的,比如著名的《终结者》系列、《黑客帝国》系列等等,如果小A只看了前一部而没有看后一部的话,他就会觉得不是很爽。准确来讲,对于任意两部不同的电影X,Y,他们可能存在一个依赖值dXY,表示如果小A看了X但是没看Y,他的体验值就会减少dXY。(注意与观看的顺序无关,只要两部都看过,就不会减少体验值)

现在他要选出若干电影来看,使得得到的总的体验值最大。如果他无法得到正的体验值,就输出0。 输入输出格式

输入格式:

输入的第一行是两个整数:电影总数N和依赖关系数目M。第二行包含用空格隔开的N个数,表示对每部电影的打分。接下来M行,每行包含三个整数X, Y, dXY,表示一个依赖关系。每个有序对(X,Y)最多出现一次。(1 ≤ X,Y ≤ N)

输出格式:

输出一个整数,表示小A能得到的最大体验值。 输入输出样例

输入样例#1: 复制

2 2 100 -50 1 2 49 2 1 10

输出样例#1: 复制

51

说明

如果小A只看电影1,体验值为100-49 = 51。如果只看电影2,体验值为-50-10 = -60。如果两部都看,体验值为100+(-50) = 50。所以应该只看电影1。

数据规模与约定

对于20%的数据,1 ≤ N ≤ 15

对于100%的数据,1 ≤ N ≤ 100, -1000 ≤ vX ≤ 1000, 0 < dXY ≤ 1000

每个测试点时限1秒

这题可以看作是最大权闭合子图的一个扩展问题 其实和那个bzoj ceoi2008 order挺像的 想了一天也没想到方法去膜了下题解 发现其实有一种情况我是可以不去考虑的 比如我这个电影的值是负数 如果选了他 没选别的 也会有一个代价 那其实这条边我是始终也不需要考虑的

我首先从源点向每个权值为正的电影连边 然后如果这个电影的权值为负数 那么我就从这个电影向汇点连边 然后如果每个电影之间存在关系 那么直接连边即可 这样的话就被转化成一个最小割问题 这个问题分为三个部分 首先是我不看这个电影带来的损失(注意如果存在关联 且没看是在现有的基础上倒扣 所以这个建图成立 其次如果存在关联 我不去看后面的电影也有可能带来损失 最后如果我必须得看这个电影 那么因为权值是负数 所以也会带来损失 跑一下最大流 用正权的总和-最大流即可

唉还是太菜啊 怎么办呢qwq

另外跪膜Icefox大佬 提供的另外一种做法 是什么呢 就是因为存在负的 所以我可以 用1000-一下每个权值 这样求出来的最小割 然后再用点数*1000- 最小割就是我想要的最大的答案了 因为这题其实我读题的时候还是有误差 觉得自己太菜了 仍然 要努力啊 做法就是 我源向每个点连 1000的 边 然后每个点向 汇连 1000-权值的边 然后 如果有限制 那么就在两个点之间直接嗯连限制的那个权值的边 然后就像我刚刚说的 用点数*1000- 最小割 为什么这么做 其实道理差不多 因为 相当于我这个点可以不选 那么我就没有收益了 这1000的边就被我割去了 如果互相之间有关联的话 如果那个权值我没有选的话 那么是不是我相当于是这1000就没了 那我还要限制一下如果选了那个点 没选这个点之间的边 要么割掉 要么不选那个点 一开始我认为这1000的权值太小了 如果我选了这个点 不选其他点的代价太大 那么会不够好 显然是不对的 因为如果我最终收益肯定<0那么我干脆哪个都不选为0即可

#include#include#include#include#define inf 0x3f3f3f3f#define N 110using namespace std;inline char gc(){ static char now[1<<16],*S,*T; if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;} return *S++;}inline int read(){ int x=0,f=1;char ch=gc(); while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();} return x*f;}struct node{ int y,z,next;}data[N*N*2];int num=1,h[N],level[N],n,m,T;inline void insert1(int x,int y,int z){ data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num; data[++num].y=x;data[num].z=0;data[num].next=h[y];h[y]=num;}inline bool bfs(){ queue q;memset(level,0,sizeof(level));level[0]=1;q.push(0); while(!q.empty()){ int x=q.front();q.pop(); for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z; if (level[y]||!z) continue;level[y]=level[x]+1;q.push(y);if (y==T) return 1; } }return 0;} inline int dfs(int x,int s){ if (x==T) return s;int ss=s; for (int i=h[x];i;i=data[i].next){ int y=data[i].y,z=data[i].z; if (level[x]+1==level[y]&&z){ int xx=dfs(y,min(s,z));if (!xx) level[y]=0; s-=xx;data[i].z-=xx;data[i^1].z+=xx;if (!s) return ss; } }return ss-s;}int main(){ freopen("3872.in","r",stdin); n=read();m=read();T=n+1;int sum=0; for (int i=1;i<=n;++i){ int tmp=read();if (tmp>=0) insert1(0,i,tmp),sum+=tmp;else insert1(i,T,-tmp); } for (int i=1;i<=m;++i){ int x=read(),y=read(),z=read(); if (z<0)continue; insert1(x,y,z); }int ans=0;while(bfs()) ans+=dfs(0,inf); printf("%d",sum-ans); return 0;}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何基于SpringBoot实现人脸识别功能
下一篇:微信公众号里“JS接口域名”实现分享功能
相关文章

 发表评论

暂时没有评论,来抢沙发吧~