[Tarjan][并查集][dp] Jzoj P4253 QYQ在艾泽拉斯

Description

在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接。
有一天,QYQ无意中发现了这些岛屿,并且发现在每个城市的地下都或多或少埋藏着一些装备、金币、宝物……
可是正当QYQ兴奋不已打算全部把它们拿走时,他却惊奇的发现你的魔法在这里被限制住了,唯一可用的技能就是闪现,而且魔法只够他使用K次这个技能了,每次使用这个技能QYQ只能从一个岛屿上闪现到另外一个岛屿上。每一个岛屿只能登上一次,QYQ可以从任何一个城市开始旅程,在任何一个城市结束旅程。
城市的数量共有n个,有m条道路,每一条道路有两个参数u,v,表示从u到v有一条道路,但你只能由u到v走,两个城市属于相同的岛屿当且仅当暂时将所有道路视为双向道路时可以从其中一个城市走到另一个城市(可以途径其它城市)。
每一个城市都有一个宝物的总价值v[i],你的任务是帮助QYQ得到最大总价值的宝物,并输出这个值。

Input

从文件azeroth.in中输入数据。
输入的第一行包含两个整数n,m
输入的第二行到第m+1行,每行包含2个整数u,v,代表你可以从城市u走到城市v
输入的第m+2行包含n个整数,第i个整数代表v[i],即这个城市的宝物总价值。
输入的第m+3行包含一个整数K,代表你可以使用技能的次数。

Output

输出到文件azeroth.out中。
输出的第一行包含一个整数,代表QYQ能获得的最大的宝物总价值

Sample Input

3 21 23 11 2 10

Sample Output

4样例说明:QYQ从3号点开始,走到2号点,最后走到1号点,结束旅程,共获得1+2+1=4价值的宝物

Data Constraint

对于30%的数据:n<=10,K=0
对于50%的数据:n<=100,m<=100,K<=1
对于100%的数据:1<=n<=100000,1<=m<=1000000,1<=v[i]<=1000,0<=K<=100000
图中可能会有重边、自环。

题解

  • 题目大意:给定一个有向有环图,每个环只能走一次,有k次在任意环上跳的次数,问可以得到的最大价值
  • 这种题,先来个Tarjan缩点,然后就变成了有向无环图,就是一个DAG
  • 然后我们只用处理每个环,也就是每个有向的连通块,进行dp,设f[i]为从第i个连通块开始能获得的最大价值
  • 那么一个有向的连通块的最大价值,就是所有在这个连通块中的所有点能获得的最大价值
  • 最后答案就是所有连通块价值的前k个之和

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N=1e5+10,M=1e6+10;
 7 int n,m,num,tot,K,Ans,cnt[2],sum[N],head[2][N],f[N],a[N],Num[N],bel[N],ans[N],fa[N],dfn[N],low[N],p[N];
 8 bool b[N],vis[N];
 9 struct edge { int x,y; }e[2][M];
10 void insert(int p,int x,int y) { e[p][++cnt[p]].x=y,e[p][cnt[p]].y=head[p][x],head[p][x]=cnt[p]; }
11 int getfather(int x) { return fa[x]==x?x:fa[x]=getfather(fa[x]); }
12 void Tarjan(int x)
13 {
14     dfn[x]=low[x]=++dfn[0],p[++tot]=x,vis[x]=1;
15     for (int i=head[0][x];i;i=e[0][i].y)
16         if (!bel[e[0][i].x])
17         {
18             if (vis[e[0][i].x]) low[x]=min(low[x],dfn[e[0][i].x]);
19             else Tarjan(e[0][i].x),low[x]=min(low[x],low[e[0][i].x]);
20         }
21     if (dfn[x]==low[x])
22     {
23         num++; int v;
24         do
25         {
26             v=p[tot--],bel[v]=num,sum[num]+=a[v],vis[v]=0;
27         }while(v!=x);
28     }
29 }
30 void work(int x)
31 {
32     b[x]=1,f[x]+=sum[x];
33     for (int i=head[1][x];i;i=e[1][i].y)
34     {
35         getfather(x),getfather(e[1][i].x);
36         fa[fa[x]]=fa[e[1][i].x],Num[e[1][i].x]--,f[e[1][i].x]=max(f[x],f[e[1][i].x]);
37         if (!Num[e[1][i].x]) work(e[1][i].x);
38     }
39 }
40 int main()
41 {
42     freopen("azeroth.in","r",stdin),freopen("azeroth.out","w",stdout),scanf("%d%d",&n,&m);
43     for (int i=1,x,y;i<=m;i++) { scanf("%d%d",&x,&y); if (x==y) continue; insert(0,x,y); }
44     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
45     scanf("%d",&K);
46     for (int i=1;i<=n;i++) if (!bel[i]) Tarjan(i);
47     for (int i=1;i<=n;i++)
48         for (int j=head[0][i];j;j=e[0][j].y)
49             if (bel[i]!=bel[e[0][j].x])
50                 insert(1,bel[i],bel[e[0][j].x]),Num[bel[e[0][j].x]]++;
51     for (int i=1;i<=num;i++) fa[i]=i;
52     for (int i=1;i<=num;i++) if (!Num[i]&!b[i]) work(i);
53     for (int i=1;i<=num;i++) getfather(i),ans[fa[i]]=max(ans[fa[i]],f[i]);
54     sort(ans+1,ans+num+1);
55     for (int i=num;i>=max(1,num-K);i--) Ans+=ans[i];
56     printf("%d",Ans);
57 }

原文地址:https://www.cnblogs.com/Comfortable/p/10339464.html

时间: 2024-07-31 04:25:15

[Tarjan][并查集][dp] Jzoj P4253 QYQ在艾泽拉斯的相关文章

poj1417(种类并查集+dp)

题目:http://poj.org/problem?id=1417 题意:输入三个数m, p, q 分别表示接下来的输入行数,天使数目,恶魔数目: 接下来m行输入形如x, y, ch,ch为yes表示x说y是天使,ch为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q):天使只说真话,恶魔只说假话: 如果不能确定所有天使的编号,输出no,若能确定,输出所有天使的编号,并且以end结尾: 注意:可能会有连续两行一样的输入:还有,若x==y,x为天使: 思路:种类并查集+

真正的骗子(并查集+dp+dp状态回溯)

[//]: # (推荐题解模板,请替换blablabla等内容 ^^) ### 题目描述 一个岛上存在着两种居民,一种是天神,一种是恶魔. 天神永远都不会说假话,而恶魔永远都不会说真话. 岛上的每一个成员都有一个整数编号(类似于身份证号,用以区分每个成员). 现在你拥有n次提问的机会,但是问题的内容只能是向其中一个居民询问另一个居民是否是天神,请你根据收集的回答判断各个居民的身份. 输入格式 输入包含多组测试用例. 每组测试用例的第一行包含三个非负整数n,p1,p2p1,p2,其中n是你可以提问

[拓扑排序][DP][Tarjan][并查集]JZOJ 4253 QYQ在艾泽拉斯

Description 在艾泽拉斯的无尽之海里,有着一群不为人知的由各个种族的冒险者统治的岛屿,这些岛屿都很庞大,足以在上面建造许多的城市,城市之间有一些单向道路连接.有一天,QYQ无意中发现了这些岛屿,并且发现在每个城市的地下都或多或少埋藏着一些装备.金币.宝物……可是正当QYQ兴奋不已打算全部把它们拿走时,他却惊奇的发现你的魔法在这里被限制住了,唯一可用的技能就是闪现,而且魔法只够他使用K次这个技能了,每次使用这个技能QYQ只能从一个岛屿上闪现到另外一个岛屿上.每一个岛屿只能登上一次,QYQ

hdu-2874 Connections between cities(lca+tarjan+并查集)

题目链接: Connections between cities Time Limit: 10000/5000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others) Problem Description After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, s

poj1417 true liars(并查集 + DP)详解

这个题做了两天了.首先用并查集分类是明白的, 不过判断是否情况唯一刚开始用的是搜索.总是超时. 后来看别人的结题报告, 才恍然大悟判断唯一得用DP. 题目大意: 一共有p1+p2个人,分成两组,一组p1个,一组p2个.给出N个条件,格式如下: x y yes表示x和y分到同一组 x y no表示x和y分到不同组 问分组情况是否唯一,若唯一则按从小到大顺序输出,否则输出no.保证不存在矛盾条件,但是有可能出现x=y的情况. 题目分析: 题中会给我们一些信息, 告诉我们那些是同一类, 哪些是不同类.

poj 1417 并查集+dp

转自:点我 题目:给出p1+p2个人,其中p1个是好人,p2个是坏人.然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人. 其中比较重要的是,好人总说真话,坏人总说假话.不需要判断矛盾.唯一解 http://poj.org/problem?id=1417 其中好人说真话,坏人说假话这点很重要. 那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人. 如果一个人说另一个人是坏人

【POJ1417】【带标记并查集+DP】True Liars

Description After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally cast ashore on a foggy island. Though he was exhausted and despaired, he was still fortunate to remember a legend of the foggy island, which h

[luogu P2170] 选学霸(并查集+dp)

题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近 输入输出格式 输入格式: 第一行,三个正整数N,M,K. 第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1-N) 输出格式: 一行,表示既不让同学们抗议,又与原来的M尽可能接

POJ 1417 True Liars(并查集+DP)

大意: 一个岛上有神与恶魔两个种族,神会说真话,恶魔会说假话.已知神与恶魔的个数,但不知道具体个人是属于哪个. n,x,y 这个人问n次 ,x为神的个数,y为恶魔的个数. 每次的问题为 xi,yi,a 问xi ,yi是否为神? a为yes/no.注意xi,yi可能为同一个人 若最终可得出哪些是神则从小到大输出神的编号,并最终输出end 否则输出no 思路: 经过简单推理可得,只要是说yes,xi,yi为同一个族,no则不为同一个族. 这样通过使用并查集+relation(relation[i]为