概述
[蓝桥杯 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(2≤n≤1000), m ( 0 ≤ m ≤ 2000 ) m(0 le m le 2000) m(0≤m≤2000),分别代表站点数,通道数。
接下来 m m m 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u,v(1 le u,v le n,uneq v) u,v(1≤u,v≤n,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
7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6
样例输出 #1
2
提示
时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛
思路:
依题意从x走到到y,有很多种走法但没关系,我们只需要分别记录所经过的各个点的次数,最后如果一个点所经过的次数等于从x走到y的不同走法数,则这个点为关键点,即每次从x走到y都需要经过这个点,即当这个点被敌人破坏后,x和 y不连通。至于储存从哪个点可以走到哪个点,我们可以用图的知识,此题为无向图。
#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
4 3
1 2
2 4
4 3
样例输出 #1
4 4 3 4
提示
- 对于 60 % 60% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 leq N,M leq 10^3 1≤N,M≤103。
- 对于 100 % 100% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 leq N,M leq 10^5 1≤N,M≤105。
思路:
此题依旧利用图的知识,不过和上一题不同,这题是有向图。这题的技巧性比较强,想到方法了就很简单,没想到的话可能就很难做出来了。本题的关键在于运用逆向思维,把边的方向反向储存,让数字更大的点去走到数字小的点,并依次传递A(v)的值。
#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
3 3
1 2
1 3
2 3
样例输出 #1
Impossible
样例 #2
样例输入 #2
3 2
1 2
2 3
样例输出 #2
1
提示
【数据规模】
对于
100
%
100%
100% 的数据,
1
≤
n
≤
1
0
4
1le n le 10^4
1≤n≤104,
1
≤
m
≤
1
0
5
1le m le 10^5
1≤m≤105,保证没有重边。
思路:
本题参考了洛谷上KesdiaelKen大佬的题解,运用链式向前星的知识。
#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
思路:
这题很简单,就不赘述了。
#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进制即可。
#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
#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
#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:
利用一元二次方程的求根公式。
思路:
利用二分搜索的知识,逐步使答案精确。
#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图 + acm第一次双周赛补题[蓝桥杯 2013 国 C] 危险系数思路:图的遍历思路:封锁阳光大学思路:Lily思路:思路:思路:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复