#专题练习# 强连通分量,缩点

#专题练习#  强连通分量,缩点 

1.洛谷   P1455 搭配购买

题目描述

明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。

输入格式

第1行n,m,w,表示n朵云,m个搭配和你现有的钱的数目

第2行至n+1行,每行ci,di表示i朵云的价钱和价值

第n+2至n+1+m ,每行ui,vi表示买ui就必须买vi,同理,如果买vi就必须买ui

输出格式

一行,表示可以获得的最大价值。

Q:题意是:有n个云朵,每个云朵有自己的价格ci 和价值di ,小明想用手里的钱买到尽可能的大的价值。但是老板的云朵们之间具有固定搭配方案,不能拆开购买。小明想知道他能购买到的最大价值是多少?

A:依题意可知,云朵之间存在搭配,即每种搭配是一个强连通分量。第一步,我们找出每个强连通分量,并计算出每个强连通分量的总价格和总价值;第二步,我们计算小明现有的钱可以买到的最大价值,显然这是一个简单的01背包,但是这里用二维背包会超时,需要用滚动数组优化为一维。这样就结束了。(好像并查集+01背包也能写,下次想起来补上。)

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<stack>
  6 using namespace std;
  7 const int maxv= 10010;
  8 const int maxe= 10100;  //可能的最大值
  9 
 10 struct ENode
 11 {
 12     int to;
 13     int Next;
 14 };
 15 ENode edegs[maxe];
 16 int Head[maxv], tnt;
 17 void init()
 18 {
 19     memset(Head, -1, sizeof(Head));
 20     tnt= -1;
 21 }
 22 void Add_ENode (int a, int b)
 23 {
 24     ++ tnt;
 25     edegs[tnt].to= b;
 26     edegs[tnt].Next= Head[a];
 27     Head[a]= tnt;
 28     ++ tnt;
 29     edegs[tnt].to= a;
 30     edegs[tnt].Next= Head[b];
 31     Head[b]= tnt;
 32 }
 33 
 34 int m;
 35 int dfn[maxv];  //深度优先搜索中顶点被访问的时间
 36 int low[maxv];  //顶点v 和它的邻接点中low[]的最小值
 37 int temp[maxv];  //判断节点是否已被访问过(0-未访问 1-已访问未删除 2-已访问已删除)
 38 int Stack[maxv];  //手动栈
 39 int TarBfs (int v, int lay, int &scc_num)
 40 {
 41     /*v: 新加入的点; lay: 时间戳; scc_num: 记录强连通分量的数量*/
 42 
 43     /*第2步:初始化dfn[v]和low[v]*/
 44     temp[v]= 1;
 45     low[v]= lay;
 46     dfn[v]= lay;
 47     Stack[++ m]= v;
 48     for (int k= Head[v]; k!= -1; k= edegs[k].Next)
 49     {
 50         /*对于v 的所有邻接节点u:*/
 51         int u= edegs[k].to;
 52         if (temp[u]== 0)
 53         {
 54             /*第2-1步:如果没有访问过,则跳转执行第2步,同时维护low[v]*/
 55             TarBfs(u, ++ lay, scc_num);
 56 
 57         }
 58         if (temp[u]== 1)
 59         {
 60             /*第2-2步:如果访问过,但没有删除,维护low[v]*/
 61             low[v]= min(low[v], low[u]);
 62         }
 63 
 64     }
 65     if (dfn[v]== low[v])
 66     {
 67         /*如果low[v]== dfn[v],则当前节点是一个强连通分量的根,
 68         那么输出相应的强连通分量。*/
 69         ++ scc_num;
 70         do
 71         {
 72             low[Stack[m]]= scc_num;
 73             temp[Stack[m]]= 2;  //已删除的节点temp更新为2
 74         }while (Stack[m --]!= v);
 75     }
 76     return 0;
 77 }
 78 
 79 int Tarjan(int n)
 80 {
 81     int scc_num= 0, lay= 1;
 82     m= 0;
 83     memset(temp, 0, sizeof(temp));
 84     memset(low, 0, sizeof(low));
 85     for (int i= 1; i<= n; i ++)
 86     {
 87         if (temp[i]== 0)
 88         {
 89             /*第1步:找一个没有被访问过的节点v,否则算法结束*/
 90             TarBfs(i, lay, scc_num);
 91         }
 92     }
 93     /*返回强连通分量的个数*/
 94     return scc_num;
 95 }
 96 
 97 int ci[maxv];
 98 int di[maxv];
 99 int rock_ci[maxv]; //每个连通块的费用和
100 int rock_di[maxv]; //每个连通块的价值和
101 int dp[10010];
102 int main()
103 {
104     int n, m, cost;
105     int a, b;
106     scanf("%d %d %d", &n, &m, &cost);
107     for (int i= 1; i<= n; i ++)
108     {
109         scanf("%d %d", &a, &b);
110         ci[i]= a;
111         di[i]= b;
112     }
113     init();
114     for (int i= 0; i< m; i ++)
115     {
116         scanf("%d %d", &a, &b);
117         Add_ENode(a, b);
118     }
119 
120     int ans= Tarjan(n);
121     memset(rock_ci, 0, sizeof(rock_ci));
122     memset(rock_di, 0, sizeof(rock_di));
123     for (int i= 1; i<= n; i ++)
124     {
125         int tmp= low[i];
126         rock_ci[tmp]+= ci[i];
127         rock_di[tmp]+= di[i];
128     }
129     int sum= 0;
130 //    for (int i= 1; i<= ans; i ++)
131 //    {
132 //        printf("--> %d %d\n", rock_ci[i], rock_di[i]);
133 //    }
134 //    cout << cost << endl;
135     for (int i= 1; i<= ans; i ++)
136     {
137         for (int j= cost; j>= 0; j --)
138         {
139             if (j- rock_ci[i]>= 0) dp[j]= max(dp[j], dp[j- rock_ci[i]]+ rock_di[i]);
140             else dp[j]= dp[j];
141 //            printf("-%d- -%d- -%d-\n", dp[i][j], dp[i- 1][j], rock_di[i]);
142         }
143     }
144     printf("%d\n", dp[cost]);
145     return 0;
146 }
Tarjan+01背包

end;

猜你喜欢

转载自www.cnblogs.com/Amaris-diana/p/11293796.html
今日推荐