強大的dfs(用處1——拓撲排序【xdoj1025】,用處二——求強聯通份量【ccf高速公路】)固然dfs用處多着咧

xdoj 1025ios

亮亮最近在玩一款叫作「夢想莊園」的經營遊戲。在遊戲中,你能夠耕種,養羊甚至建造紡織廠。
若是你須要製造衣服,你首先得有布匹和毛線。布匹由棉花紡織而成;毛線由羊毛製成,而羊須要飼料才能長出羊毛,最終飼料由小麥和胡蘿蔔製成。
  假設遊戲中共有N種物品,第i種物品由其餘Ci個物品製成。亮亮須要你幫他製做M個任務物品來完成銷售訂單。
遊戲中的每一個物品都有一個價格Vi,當原材料不足以製做出全部的物品時,你須要花盡可能少的錢買一些物品來完成任務。你能夠選擇直接購買所需的任務物品,也能夠購買其餘物品來製做任務物品,可是每製做一次須要W的代價。
 

題目分析:看着好嚇人啊。。其實分析清晰也很簡單。每種物體既能夠直接買到或者由其餘物體制做獲得。那麼咱們就取二者的最小值。製做的花費咱們能夠這樣求得
若是x的原材料有y 那麼x和y之間有一條有向邊 。而後按照拓撲排序的順序自底而上求出各個物體制做所需的價值。。很簡單嗎?!
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <vector>
 6 using namespace std;
 7 const int N=1e4+7;
 8 vector < vector <int> > g(N);
 9 int val[N];
10 bool vis[N];
11 int n,m,w;
12 void dfs (int rt) {
13     vis[rt]=1;
14     if (g[rt].size()==0) return ;// 最底層直接返回
15     int cost=w;
16     for (int i=0;i<g[rt].size();i++) {
17         int next=g[rt][i];
18         if (!vis[next])  dfs(next);
19         cost+=val[next];//cost製做費用
20     }
21     val[rt]=min (cost,val[rt]);//取二者最小值
22     return ;
23 }
24 int main ()
25 {
26     int T;
27     scanf ("%d",&T);
28     while (T--) {
29         scanf ("%d %d %d",&n,&m,&w);
30         for (int i=0;i<n;i++) g[i].clear();
31         memset (vis,0,sizeof(vis));
32         for (int i=0;i<n;i++) {
33             scanf ("%d",&val[i]);
34             int num; scanf ("%d",&num);
35             for (int j=0;j<num;j++) {
36                 int u; scanf ("%d",&u);
37                 g[i].push_back(u);
38             }
39         }
40         for (int i=0;i<n;i++) 
41             if (!vis[i])  dfs (i);
42         int sum=0;
43         for (int i=0;i<m;i++) {
44             int x; scanf ("%d",&x);
45             sum+=val[x];
46         }
47         printf ("%d\n",sum);
48     }
49     return 0;
50 }

ccf 高速公路 求聯通份量 這個算法好像叫trajin 向這些科學家致敬算法

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <stack>
 5 #include <vector>
 6 using namespace std;
 7 const int N=1e4+7;
 8 vector < vector <int> > g(N);
 9 stack <int> ss;
10 bool instack[N];
11 bool vis[N];
12 int dfn[N],low[N];// dfn 保存遍歷序號  low 這個點所能到達的最小點  
13 int ans;
14 int n,m;
15 int cnt;//訪問順序
16 void dfs (int rt) {
17     vis[rt]=1;
18     instack[rt]=1; ss.push(rt);
19     dfn[rt]=low[rt]=++cnt;
20     for (int i=0;i<g[rt].size();i++) {
21         int next=g[rt][i];
22         if (!vis[next]) {
23             dfs (next);
24             low[rt]=min (low[rt],low[next]);
25         }
26         else if (instack[next]) {
27             low[rt]=min (low[rt],low[next]);
28         }
29     }
30     if (dfn[rt]==low[rt]) {// dfn[rt]==low[rt] 表示遍歷一個聯通分變量啦
31         int num=1;
32         int tmp=ss.top(); ss.pop(); instack[tmp]=0;//在棧中 說明這個點的後繼子孫尚未訪問完
33         while (dfn[tmp]!=low[tmp]) { num++; tmp=ss.top(); ss.pop(); instack[tmp]=0;}
34         ans+=(num-1)*num/2;
35     }
36     return ;
37 }
38 int main ()
39 {
40     ios::sync_with_stdio(false);
41     cin>>n>>m;
42     for (int i=1;i<=m;i++) {
43         int x,y; cin>>x>>y;
44         g[x].push_back(y);
45     }
46     for (int i=1;i<=n;i++)
47         if (!vis[i]) dfs (i);
48     printf ("%d\n",ans);
49     return 0;
50 }
相關文章
相關標籤/搜索