我是靠谱客的博主 俏皮毛豆,这篇文章主要介绍Week5图 + acm第一次双周赛补题[蓝桥杯 2013 国 C] 危险系数思路:图的遍历思路:封锁阳光大学思路:Lily思路:思路:思路:,现在分享给大家,希望可以做个参考。

[蓝桥杯 2013 国 C] 危险系数

题目背景

抗日战争时期,冀中平原的地道战曾发挥重要作用。

题目描述

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数 D F ( x , y ) DF(x,y) DF(x,y)

对于两个站点 x x x y ( x ≠ y ) , y(xneq y), y(x=y), 如果能找到一个站点 z z z,当 z z z 被敌人破坏后, x x x y y y 不连通,那么我们称 z z z 为关于 x , y x,y x,y 的关键点。相应的,对于任意一对站点 x x x y y y,危险系数 D F ( x , y ) DF(x,y) DF(x,y) 就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式

输入数据第一行包含 2 2 2 个整数 n ( 2 ≤ n ≤ 1000 ) n(2 le n le 1000) n(2n1000) m ( 0 ≤ m ≤ 2000 ) m(0 le m le 2000) m(0m2000),分别代表站点数,通道数。

接下来 m m m 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u,v(1 le u,v le n,uneq v) u,v(1u,vn,u=v) 代表一条通道。

最后 1 1 1 行,两个数 u , v u,v u,v,代表询问两点之间的危险系数 D F ( u , v ) DF(u,v) DF(u,v)

输出格式

一个整数,如果询问的两点不连通则输出 − 1 -1 1

样例 #1

样例输入 #1

复制代码
1
2
3
4
5
6
7
8
9
7 6 1 3 2 3 3 4 3 5 4 5 5 6 1 6

样例输出 #1

复制代码
1
2
2

提示

时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛

思路:

依题意从x走到到y,有很多种走法但没关系,我们只需要分别记录所经过的各个点的次数,最后如果一个点所经过的次数等于从x走到y的不同走法数,则这个点为关键点,即每次从x走到y都需要经过这个点,即当这个点被敌人破坏后,x和 y不连通。至于储存从哪个点可以走到哪个点,我们可以用图的知识,此题为无向图。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<iostream> #include<vector> using namespace std; vector <int> a[1000]; //数组a的每一个元素都是一个vector容器 int vis[1000]={0}; //用于标记某点是否已经走过 int cnt[1000]={0}; //记录走过某个点的次数 int ed,total=0; //ed为终点,total表示走法数 int n,m; void dfs(int now) //深度优先搜索 { if(now==ed) //确定搜索出口 { total++; for(int i=1;i<=n;i++) { if(vis[i])cnt[i]++; //若在这一次走法中i点走过则cnt【i】++ } return; } for(int i=0;i<a[now].size();i++) { int next=a[now][i]; //走到下一个点 if(vis[next]==0) //判断下一个点是否走过 { vis[next]=1; dfs(next); //递归思想 vis[next]=0; //这一步很重要一定不能漏了! } } } int main() { cin>>n>>m; for(int i=0;i<m;i++) { int x,y; cin>>x>>y; a[x].push_back(y); //注意这是无向图 a[y].push_back(x); } int st; cin>>st>>ed; //起点st,终点ed vis[st]=1; //先标记起点已走过 dfs(st); int ans=0; //ans记录关键点的个数 for(int i=1;i<=n;i++) { if(cnt[i]==total)ans++; } ans-=2; //排除起点和终点这两个点 cout<<ans; return 0; }

图的遍历

题目描述

给出 N N N 个点, M M M 条边的有向图,对于每个点 v v v,求 A ( v ) A(v) A(v) 表示从点 v v v 出发,能到达的编号最大的点。

输入格式

1 1 1 2 2 2 个整数 N , M N,M N,M,表示点数和边数。

接下来 M M M 行,每行 2 2 2 个整数 U i , V i U_i,V_i Ui,Vi,表示边 ( U i , V i ) (U_i,V_i) (Ui,Vi)。点用 1 , 2 , … , N 1,2,dots,N 1,2,,N 编号。

输出格式

一行 N N N 个整数 A ( 1 ) , A ( 2 ) , … , A ( N ) A(1),A(2),dots,A(N) A(1),A(2),,A(N)

样例 #1

样例输入 #1

复制代码
1
2
3
4
5
4 3 1 2 2 4 4 3

样例输出 #1

复制代码
1
2
4 4 3 4

提示

  • 对于 60 % 60% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 leq N,M leq 10^3 1N,M103
  • 对于 100 % 100% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 leq N,M leq 10^5 1N,M105

思路:

此题依旧利用图的知识,不过和上一题不同,这题是有向图。这题的技巧性比较强,想到方法了就很简单,没想到的话可能就很难做出来了。本题的关键在于运用逆向思维,把边的方向反向储存,让数字更大的点去走到数字小的点,并依次传递A(v)的值。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<iostream> #include<vector> using namespace std; const int N=100001;//本人在这里掉过坑,建议不要打擦边球,数组尽量开大一点 vector <int> a[N]; //储存有向图的点和边 int n,m; int ma[N]={0}; //ma[j]表示某一点j能走到的最大的点 int vis[N]={0}; void dfs(int now) //简单的深度搜索 { for(int i=0;i<a[now].size();i++) { int to=a[now][i]; if(vis[to]==0) { vis[to]=1; ma[to]=ma[now]; dfs(to); } } } int main() { cin>>n>>m; for(int i=0;i<m;i++) { int u,v; cin>>u>>v; a[v].push_back(u); //逆向思维,反向储存边 } for(int i=n;i>=1;i--) //注意是从数字大的点开始遍历 { if(vis[i]==0) //判断点i是否已经走过 { ma[i]=i; //先初始化 dfs(i); vis[i]=1; //标记点i已经走过了 } } for(int i=1;i<n;i++)cout<<ma[i]<<' '; cout<<ma[n]; return 0; }

封锁阳光大学

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由 n n n 个点构成的无向图, n n n 个点之间由 m m m 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入格式

第一行两个正整数,表示节点数和边数。
接下来 m m m 行,每行两个整数 u , v u,v u,v,表示点 u u u 到点 v v v 之间有道路相连。

输出格式

仅一行如果河蟹无法封锁所有道路,则输出 Impossible,否则输出一个整数,表示最少需要多少只河蟹。

样例 #1

样例输入 #1

复制代码
1
2
3
4
5
3 3 1 2 1 3 2 3

样例输出 #1

复制代码
1
2
Impossible

样例 #2

样例输入 #2

复制代码
1
2
3
4
3 2 1 2 2 3

样例输出 #2

复制代码
1
2
1

提示

【数据规模】
对于 100 % 100% 100% 的数据, 1 ≤ n ≤ 1 0 4 1le n le 10^4 1n104 1 ≤ m ≤ 1 0 5 1le m le 10^5 1m105,保证没有重边。

思路:

本题参考了洛谷上KesdiaelKen大佬的题解,运用链式向前星的知识。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<cstdio> #include<iostream> #include<cmath> #include<string> #include<algorithm> using namespace std; struct Edge { int t; int nexty; }edge[200000]; int head[20000]; int cnt=0;//链式前向星 void add(int a,int b)//存边 { cnt++; edge[cnt].t=b; edge[cnt].nexty=head[a]; head[a]=cnt; } bool used[20000]={0};//是否遍历过 int col[20000]={0};//每一个点的染色 int sum[2];//黑白两种染色各自的点数 bool dfs(int node,int color)//染色(返回false即impossible) { if(used[node])//如果已被染过色 { if(col[node]==color)return true;//如果仍是原来的颜色,即可行 return false;//非原来的颜色,即产生了冲突,不可行 } used[node]=true;//记录 sum[col[node]=color]++;//这一种颜色的个数加1,且此点的颜色也记录下来 bool tf=true;//是否可行 for(int i=head[node];i!=0&&tf;i=edge[i].nexty)//遍历边 { tf=tf&&dfs(edge[i].t,1-color);//是否可以继续染色 } return tf;//返回是否完成染色 } int main() { int n,m; scanf("%d%d",&n,&m); int a,b; while(m--) { scanf("%d%d",&a,&b); add(a,b); add(b,a);//存的是有向边,所以存两次 } int ans=0; for(int i=1;i<=n;i++) { if(used[i])continue;//如果此点已被包含为一个已经被遍历过的子图,则不需重复遍历 sum[0]=sum[1]=0;//初始化 if(!dfs(i,0))//如果不能染色 { printf("Impossible"); return 0;//直接跳出 } ans+=min(sum[0],sum[1]);//加上小的一个 } printf("%d",ans);//输出答案 return 0; }

Lily

百合花(Lily)是一种美丽的花。她通常一年只开一次花,所以如果你看到百合花盛开,它会非常珍贵。然而,她对猫有剧毒,所以你必须注意让好奇的猫远离可爱的百合花。

你有n个网格的土壤土地排成一行,从1到n,其中一些是百合花。我们不想伤害百合,也不想伤害猫。你可以在网格上放一些猫粮,但对于任何有猫粮的网格i,在区域[i−1,i+1]不得含有百合花。你喜欢猫和百合,所以你想最大限度地增加有猫粮的格子。

设计满足上述要求的计划。

输入格式:

有一个整数n(1≤n≤1000)表示网格的数量。

第二行包含仅由“L”和“.”组成的字符串R,表示有和没有百合花的格子。

输出格式:

输出包含一行,字符串R′仅由“L”、“”组成和“C”,其中“C”表示在满足上述要求的同时分配给R中空网格的猫粮。

输入样例:

在这里给出一组输入。例如:

5
…L…

输出样例:

在这里给出相应的输出。例如:

C.L.C

思路:

这题很简单,就不赘述了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream> using namespace std; int main() { int n; string r; cin>>n>>r; for(int i=0;i<n;i++) { if(r[i]=='.'&&(i==0&&r[i+1]!='L'||i==n-1&&r[i-1]!='L'||r[i-1]!='L'&&r[i+1]!='L')) r[i]='C'; } if(n==1&&r[0]=='.')cout<<'C'; else cout<<r; return 0; }

a * b

给出两个不超过1000位的十六进制数a,b。
求a∗b的值

输入格式:

输入共两行,两个十六进制的数

输出格式:

输出一行,表示a∗b

输入样例:

在这里给出一组输入。例如:

1BF52
1D4B42

输出样例:

在这里给出相应的输出。例如:
332FCA5924

思路:

数字位数太大,考虑用数组储存每一位数,转化为10进制后用小学就学过的竖式乘法计算结果,最后转化为16进制即可。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<bits/stdc++.h> using namespace std; int main() { static int num[1001],num2[1001],num3[2333]; char n[1001]; char n2[1001]; cin>>n>>n2; int l2=strlen(n2),l=strlen(n); if(l<l2) { swap(l,l2); swap(n,n2); } for(int i=l;i>=1;i--) { if(n[i-1]>='0'&&n[i-1]<='9') { num[l-i+1]=n[i-1]-'0'; } else { num[l-i+1]=n[i-1]-'A'+10; } } for(int i=1;i<=l;i++) { if(num[i]>15) { num[i+1]++; num[i]%=16; continue; } break; } for(int i=l2;i>=1;i--) { if(n2[i-1]>='0'&&n2[i-1]<='9') { num2[l2-i+1]=n2[i-1]-'0'; } else { num2[l2-i+1]=n2[i-1]-'A'+10; } } for(int i=1;i<=l2;i++) { if(num2[i]>15) { num2[i+1]++; num2[i]%=16; continue; } break; } int flag=0; for(int i=1;i<=l2;i++) { for(int j=1;j<=l;j++) { flag=(num[j]*num2[i]+num3[j+i-1])/16; num3[j+i-1]=(num[j]*num2[i]+num3[j+i-1])%16; num3[j+i]+=flag; } } int flag2=2333; while(num3[flag2]==0) {flag2--;} for(int i=flag2;i>0;i--) { if(!(i==flag2&&num3[i]==0)) { if(num3[i]>9) { cout<<(char)(num3[i]-10+'A'); } else { cout<<num3[i]; } } } }

山头狙击战

题目描述

小明为了掩护大部队,单枪匹马同敌人周旋,后来被敌人包围在某山头……等等,为什么怎么听怎么像狼牙山五壮士!不过不用着急,这次小明携带了足够的弹药,完全可以将涌上来的敌人一个一个干掉。小明是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑和面子问题,小明会等待敌人靠近然后射击。
正当小明为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花k秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时小明无法将他击毙,那么我们可怜的小明就将牺牲在敌人的刺刀下。现在小明用心灵感应向你发出求助:要保住自己的性命并且歼灭所有敌人,小明最多只能用多少时间给枪装上一发子弹?
说明:假设一开始小明的枪中就有一发子弹,并且一旦确定一个装弹时间,小明始终会用这个时间完成子弹的装卸。希望你能帮助小明脱离险境。

输入格式

每组输入数据,第一行有两个整数n和m,(2≤n≤100,000; 1≤m≤10,000,000)n代表敌人个数,m代表小明的射程。
接下来有n行,每行一个整数mi,(1≤mi≤10,000,000),代表每个敌人一开始相对山头的距离(单位为米)。

输出格式

每组输出数据仅有一个整数,代表小明的换弹时间(单位为秒)。

样例输入

6 100
236
120
120
120
120
120

样例输出

25

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h> using namespace std; int n,d; bool ccc(int a,int b) { return a>b; } int check(long long s[],long long x) { long long t=s[0]-d; if(t<0) {t=0;} t+=x; for(int i=1;i<n;i++) { if(s[i]-t>d) {t+=s[i]-t-d;} else if(s[i]-t<0) {return 0;} t+=x; } return 1; } int main() { cin>>n>>d; long long s[n]; for(int i=0;i<n;i++) { cin>>s[i]; } sort(s,s+n); long long l=1,r=1e8,mid,ans=0; while(l<=r) { mid=(l+r)/2; if(check(s,mid)) { l=mid+1; ans=max(mid,ans); } else { r=mid-1; } } cout<<ans; }

Reversing Linked List

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤10
5
) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.

Output Specification:

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+2; int s,n,k; struct tt { int last,next=-2,id; }t[maxn]; void exchange(int a) { int c=a,d=0,i=a,k2; for(int j=1;j<=k;j++) { k2=t[i].last; swap(t[i].last,t[i].next); if(j==k) {d=i;} i=k2; } swap(t[c].last,t[d].next); if(t[d].next!=-1) { t[t[d].next].last=d; } } int main() { cin>>s>>n>>k; for(int i=0;i<n;i++) { tt ttt; int a; cin>>a>>ttt.id>>ttt.next; t[a].next=ttt.next; t[a].id=ttt.id; } t[s].last=-2; int js=0; for(int i=s;i>=0;i=t[i].next) { js++; if(t[i].next==-1) {break;} } n=js; js=0; int js2; for(int i=s;i>=0;i=t[i].next) { js++; if(js==n-n%k) { js2=i; } if(t[i].next==-1) {break;} t[t[i].next].last=i; } for(int q=1;q<=n/k;q++) { exchange(js2); if(t[js2].last!=-2) { t[t[js2].last].next=js2; } if(q==n/k) { } else { js2=t[js2].last; } } for(int i=js2;i>=0;i=t[i].next) { printf("%.5d %d ",i,t[i].id); if(t[i].next<0) { cout<<t[i].next<<endl; } else { printf("%.5dn",t[i].next); } } }

一元三次方程

给定一个形如ax3+bx2+cx+d=0的一元三次方程。

已知该方程有三个不同的实数根(根与根之差的绝对值≥10 −6),且根范围均在[p,q]之间,你需要解出这个方程的三个根。

输入格式:

第一行一个整数T(1≤T≤1000),表示有T组数据

接下来T行,每行6个实数,分别表示a,b,c,d,p,q

数据保证:−10 2≤p,q≤10 2
,且对于∀x∈[p,q],−106≤f(x)≤10 6

输出格式:

输出三个实数,表示方程的三个解。

你的答案可以以任意顺序输出。

一个答案被认为是正确的,当且仅当其与标准答案的绝对误差不超过10 −6

输入样例:

在这里给出一组输入。例如:

1
1.000000 -5.000000 -4.000000 20.000000 -10.000000 10.000000

输出样例:

在这里给出相应的输出。例如:

-2.000000 2.000000 5.000000
提示1:
样例所给方程的图像如下:

(略)

提示2:

利用一元二次方程的求根公式。

思路:

利用二分搜索的知识,逐步使答案精确。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h> using namespace std; double a,b,c,d,p,q; double f(double x) { return a*pow(x,3)+b*pow(x,2)+c*x+d; } int main() { int n; double eps=1e-7; cin>>n; for(int k=0;k<n;k++) { int flag=1; cin>>a>>b>>c>>d>>p>>q; double x1=(-2*b-sqrt(4*b*b-12*a*c))/(6*a); double x2=(-2*b+sqrt(4*b*b-12*a*c))/(6*a); if(x1>x2) {swap(x1,x2);} if(f(x1)<0) {flag=-1;} double l,r,mid; for(int aa=1;aa<=3;aa++) { if(aa==1) {l=p,r=x1;} else if(aa==2) {l=x1,r=x2,flag=-flag;} else if(aa==3) {l=x2,r=q,flag=-flag;} while(r-l>=eps) { mid=(l+r)/2; if(f(mid)*flag<0) { l=mid+eps; } else { r=mid-eps; } } printf("%.6lf ",mid); } printf("n"); } }

最后

以上就是俏皮毛豆最近收集整理的关于Week5图 + acm第一次双周赛补题[蓝桥杯 2013 国 C] 危险系数思路:图的遍历思路:封锁阳光大学思路:Lily思路:思路:思路:的全部内容,更多相关Week5图内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部