图论1

A.能量树

时间限制: 1000ms
空间限制: 262144kB

题目描述

时间:1s 空间:256M

题目描述:

小信有 n 个节点的有根能量树,根为 1。最开始,树上每个节点的能量都是 0

现在小信有 n 个能量球,第 i 个能量球拥有 vi 能量。她想把这 n 个能量球分别放置在能量树的每个节点上,使能量树的每个节点都恰好有一个能量球。

小信每次只能放置一个能量球,所以她将进行 n 次操作。每一次操作,她会选择一个能量球,再选择一个没有能量球的能量树节点 x,把刚刚选择的能量球放置在节点 x 上。在这之后,小信能获得以 x 为根的子树中的所有能量球的能量 (包括节点 x 的能量球能量)。

在放置完所有能量球后,小信可能获得的总能量最多是多少?

输入格式:

第一行包含一个整数 n (1n210^5)。

第二行包含 n1 个整数 2,3,…,f2,f3,,fn (1fii1),表示节点 i 的父亲是 fi

第三行包含 n 个整数 1,2,…,v1,v2,,vn (1vi10^5),分别表示能量球的能量。

输出格式:

输出一个整数,表示小信可能获得的最多总能量。

样例输入:

5 1 1 3 3 1 1 2 2 3

样例输出:

22

提示:

样例解释:

能量树如图所示。

第一次操作,小信选择 3 号能量球,它的能量为 2,把它放置在节点 2。在这之后,小信能获得节点 2 中能量球的能量,共 2 能量。

第二次操作,小信选择 4 号能量球,它的能量为 2,把它放置在节点 5。在这之后,小信能获得节点 5 中能量球的能量,共 2 能量。

第三次操作,小信选择 5 号能量球,它的能量为 3,把它放置在节点 4。在这之后,小信能获得节点 4 中能量球的能量,共 3 能量。

第四次操作,小信选择 1 号能量球,它的能量为 1,把它放置在节点 3。在这之后,小信能获得节点 345 中能量球的能量,共 1+2+3=6 能量。

第五次操作,小信选择 2 号能量球,它的能量为 1,把它放置在节点 1。在这之后,小信能获得节点 12345 中能量球的能量,共 1+2+1+2+3=9 能量。

所以小信总共获得了 2+2+3+6+9=22 能量。

操作方案不唯一,但可以证明没有操作能获得比 22 更多的总能量,所以答案为 22

 

①DFS/BFS 求出每个点到根的距离,排序:大对大(大能量放离根结点远的点)

②求和

 

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int N=2e5+10;
 5 vector<int> q[N];
 6 int ar[N],n;
 7 int f[N];
 8 vector<int> e;
 9 bool st[N];
10 int sum;
11 inline void dfs(int x){
12     st[x]=true;
13     for(int i=0;i<q[x].size();i++){
14         int xx=q[x][i];
15         if(!st[xx]){
16             dfs(xx);
17             f[x]+=f[xx];
18         }
19     }
20     sum+=f[x];
21 }
22 inline void bfs(int x){
23     queue<int> p;
24     p.push(x);
25     st[x]=true;
26     while(!p.empty()){
27         int t=p.front();
28         p.pop();
29         e.push_back(t);
30         for(int i=0;i<q[t].size();i++){
31             int xx=q[t][i];
32             if(!st[xx]){
33                 st[xx]=true;
34                 p.push(xx);
35             }
36         }
37     }
38 }
39 inline void solve(){
40     cin>>n;
41     for(int i=2;i<=n;i++){
42         int a;
43         cin>>a;
44         q[i].push_back(a);
45         q[a].push_back(i);
46     }
47     for(int i=1;i<=n;i++) cin>>ar[i];
48     sort(ar+1,ar+1+n);
49     bfs(1);
50     for(int i=0;i<n;i++) f[e[i]]=ar[i+1];
51     memset(st,0,sizeof st);
52     dfs(1);
53     cout<<sum<<"\n";
54 }
55 signed main(){
56     solve();
57     return 0;
58 }
AC Code

 

B.旅游路线的数量

时间限制: 2000ms
空间限制: 262144kB

题目描述

时间:2s 空间:256M

题目描述:

一个国家有 n 个城市,城市与城市之间有一些道路,总共有 m 条。

小信在城市 1 ,他想知道从城市 1 出发,有多少条不同的旅游线路,并且要求旅游线路中不能经过同一个城市两次。

可能有很多这样的旅游线路,如果超过 10^6 条,你只需要告诉小信有 10^6 条即可。

 

输入格式:

第一行包含两个整数 n, m (1n210^5, 0mmin(210^5,n(n1)/2))。

接下来 m 行,每行两个整数 ui ,vi (1ui,vin),表示城市 u 与 城市 v 之间有一条无向道路。

保证没有重边和自环。

 

输出格式:

对于每组测试数据,输出一个整数表示答案。

 

样例1输入:

4 2
1 2
2 3

样例1输出:

3

样例2输入:

4 6
1 2
1 3
1 4
2 3
2 4
3 4

样例2输出:

16

样例3输入:

8 21
2 6
1 3
5 6
3 8
3 6
4 7
4 6
3 4
1 5
2 4
1 2
2 7
1 4
3 5
2 5
2 3
4 5
3 7
6 7
5 7
2 8

样例3输出:

2023

 

拿样例一举例:

1

1,2

1,3

1,4

1,2,3

1,3,2

1,3,4

1,4,3

1,2,4

1,4,2

1,2,3,4

1,3,2,4

1,4,2,3

1,2,4,3

1,3,4,2

1,4,3,2

共16种

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int N=2e5+10;
 5 int n,m;
 6 vector<int> q[N];
 7 int dist[N];
 8 int res=0;
 9 bool st[N];
10 inline void dfs(int x){
11     res++;
12     st[x]=true;
13     if(res>=1000000){
14         puts("1000000"); exit(0);
15     }
16     for(int i=0;i<q[x].size();i++){
17         int e=q[x][i];
18         if(!st[e]){
19             dfs(e);
20         }
21     }
22     st[x]=false;
23 }
24 inline void solve(){
25     cin>>n>>m;
26     for(int i=1;i<=m;i++){
27         int a,b;
28         cin>>a>>b;
29         q[a].push_back(b);
30         q[b].push_back(a);
31     }
32     dfs(1);
33     cout<<res<<"\n";
34 }
35 signed main(){
36     solve();
37     return 0;
38 }
AC Code

 

C.小信跳房子

时间限制: 1000ms
空间限制: 262144kB

题目描述

时间:1s 空间:256M

题目描述:

小信在玩跳房子游戏,已知跳房子游戏的图表现为一颗完美的具有2^(10^100)1个节点的二叉树。从根节点依次编号为1,2,...,2^(10^100)1。节点(1i≤2^(10^100)1)的左子节点编号为2i,右子节点编号为2i+1。

小信从从节点x出发,共n步,用一个长度为n的字符串表示小信的移动方向,“U”表示跳到当前所在节点的父节点,“L”表示跳到当前节点的左子节点,“R”表示跳到当前节点的右子节点。

输出小信在跳了n步之后所处的节点编号,保证最终答案不超过10^18。

提示:在跳的过程中节点编号可能超过10^18。

输入格式:

第一行包含两个整数\n,x,表示小信移动次数和初始所在节点编号。

第二行包含一个只含“U”,“L”和“R”的长为n的字符串S。

 

输出格式:

输出一个整数,表示小信在跳了n步之后所处的节点编号。

 

样例1输入:

3 2
URL

样例1输出:

6

样例2输入:

6 500000000000000000
RRRUUU

样例2输出:

500000000000000000

约定与提示:

对于100%的数据,1n10^6;1x10^18。

 

样例1:小信的移动路径是2 -> 1 -> 3 -> 6

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int N=1e6+10;
 5 int n,x;
 6 char ar[N];
 7 bool st[N];
 8 inline void solve(){
 9     cin>>n>>x;
10     for(int i=1;i<=n;i++){
11         cin>>ar[i];
12     }
13     stack<int> q;
14     for(int i=n;i>=1;i--){
15         if(ar[i]=='U') q.push(i);
16         else{
17             if(!q.empty()){
18                 st[q.top()]=true;
19                 q.pop();
20                 st[i]=true;
21             }
22         }
23     }
24     for(int i=1;i<=n;i++){
25         if(!st[i]){
26             if(ar[i]=='U') x/=2;
27             else if(ar[i]=='L') x*=2;
28             else x=x*2+1;
29         }
30     }
31     cout<<x<<"\n";
32 }
33 signed main(){
34     solve();
35     return 0;
36 }
AC Code

 

 D.虫族据点

时间限制: 1000ms
空间限制: 524288kB

题目描述

题目描述

阿斯罗菲克帝国南疆毗邻幽暗森林,其中虫豸横行。

帝宫总管萨拉温格探查发现,虫族似乎已经在森林中建立了 n 个据点,在这些据点之间还有 m 条道路 (双向道路) 供虫族通行。萨拉温格还发现,若 k 个据点之间两两相连,且这 k 个据点与其它任何一个据点都没有道路相连,则这 k 个据点中必然居住了一名虫族大祭司。不论这个 k 是多少,哪怕 k=1,也一定有一名大祭司。

请问总共有几名大祭司。

输入格式

第一行两个整数 n 和 m,接下来 m 行每行两个整数表示一条已经存在的路径。

输出格式

输出一行一个整数,表示大祭司的数量。

样例输入1

6 4
0 1
0 2
1 2
3 4

样例输出1

3

0-1-2,3-4,5 各有一名大祭司。

样例输入2

6 5
0 1
0 2
1 2
3 4
3 5

样例输出2

1

0-1-2 有一名大祭司。

数据规模

1n100

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=110;
 4 vector<int> q[N];
 5 int n,m;
 6 bool st[N];
 7 vector<int> p;
 8 int ar[N],br[N];
 9 int cr[N];
10 inline void dfs(int x){
11     st[x]=true;
12     p.push_back(x);
13     for(int i=0;i<q[x].size();i++){
14         int e=q[x][i];
15         if(!st[e]){
16             dfs(e);
17         }
18     }
19 }
20 inline void solve(){
21     cin>>n>>m;
22     for(int i=1;i<=m;i++){
23         int a,b;
24         cin>>a>>b;a+=1;b+=1;
25         q[a].push_back(b);
26         q[b].push_back(a);
27         cr[a]++;cr[b]++;
28     }
29     int res=0;
30     for(int i=1;i<=n;i++){
31         if(!st[i]){
32             p.clear();
33             dfs(i);
34             int flag=0;
35             int xx=p.size();
36             for(int j=0;j<xx;j++){
37                 if(cr[p[j]]!=xx-1) flag=1;
38             }
39             if(!flag) res++;
40         }
41     }
42     cout<<res;
43 }
44 signed main(){
45     solve();
46     return 0;
47 }
AC Code

                                                                 

 

 

posted @ 2023-12-30 20:33  Tinx  阅读(144)  评论(0)    收藏  举报