牛客练习赛27
A-纸牌
题目描述
小w想和你van纸牌
小w有两张纸牌,两张纸牌上都有相同的正整数n
每一轮一张纸牌上的数都可以减去小于等于另外一张纸牌上的数的数
每一轮只能操作和上轮不同的纸牌
小w想知道三轮之后两纸牌上数字之和的最小值
注意,不能减为负数
输入描述:
第一行1个正整数n。
输出描述:
一行一个整数
表示三轮之后两纸牌上数字和的最小值
示例1
输入
2
输出
1
说明
样例解释:两张ab上数字分别为2,第一轮,a张减去1(1 <= (b = 2)) 第二轮b减去1(1 <= (a = 1)) ,第三轮a减去1(1 <= (b = 1)),游戏结束a+b = 1,该结果为最可行优解之一
备注:
保证1 ≤ n ≤ 1000000000
解题思路:题目很简单,因为只有三轮,所以手动模拟几个样例就可以得出结果。贴一下题解:k≤n-x表示后手第1次减少的数字必须不大于先手第1次剩下的数字,为了使得先手第2次剩下的数字能减到0,那么必须满足先手第1次剩下的数字不大于后手第1次剩下的数字。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 int n; 5 while(cin>>n){ 6 cout<<(n+1)/2<<endl; 7 } 8 return 0; 9 }
C-水图
题目描述
小w不会离散数学,所以她van的图论游戏是送分的
小w有一张n个点n-1条边的无向联通图,每个点编号为1~n,每条边都有一个长度
小w现在在点x上
她想知道从点x出发经过每个点至少一次,最少需要走多少路
小w现在在点x上
她想知道从点x出发经过每个点至少一次,最少需要走多少路
输入描述:
第一行两个整数 n,x,代表点数,和小w所处的位置
第二到第n行,每行三个整数 u,v,w,表示u和v之间有一条长为w的道路
输出描述:
一个数表示答案
示例1
输入
3 1 1 2 1 2 3 1
输出
2
备注:
1 ≤ n ≤ 50000 , 1 ≤ w ≤ 2147483647
解题思路:最长链变形,2次bfs。先以w为根节点,第一次深搜必将达到树的直径的一端点maxvex,然后再以maxvex为根节点,第二次深搜必将达到树的直径的另一端点,则w到达这两端点的最短距离为tmp,那么取剩下的最长链的距离为maxcap-tmp必将经过一次,其他边必都经过两次。因此,最后的公式为maxcap-tmp+(sum-maxcap+tmp)*2。
AC代码:
1 #include<iostream> 2 #include<queue> 3 #include<string.h> 4 #include<cstdio> 5 using namespace std; 6 const int maxn=5e4+5; 7 struct EDGE{int to,cap,next;}edge[maxn<<1]; 8 struct node{ 9 int u,tot; 10 node(int x,int y):u(x),tot(y){} 11 }; 12 int n,x,y,w,q,cnt,res,maxcap,maxvex,sum,head[maxn];bool vis[maxn]; 13 queue<node> que; 14 void add_edge(int u,int v,int w){ 15 edge[cnt].to=v; 16 edge[cnt].cap=w; 17 edge[cnt].next=head[u]; 18 head[u]=cnt++; 19 } 20 void bfs(int u,int cap,int &maxcap,int &maxvex){ 21 while(!que.empty())que.pop(); 22 memset(vis,false,sizeof(vis)); 23 que.push(node(u,cap));vis[u]=true; 24 while(!que.empty()){ 25 node nod=que.front();que.pop(); 26 for(int i=head[nod.u];~i;i=edge[i].next){ 27 int v=edge[i].to; 28 if(!vis[v]){ 29 vis[v]=true; 30 que.push(node(v,nod.tot+edge[i].cap)); 31 } 32 } 33 if(nod.tot>maxcap)maxcap=nod.tot,maxvex=nod.u; 34 } 35 } 36 int main(){ 37 while(~scanf("%d%d",&n,&q)){ 38 memset(head,-1,sizeof(head));cnt=sum=0; 39 while(--n){ 40 scanf("%d %d %d",&x,&y,&w); 41 add_edge(x,y,w); 42 add_edge(y,x,w); 43 sum+=w; 44 } 45 maxcap=0,maxvex=1; 46 bfs(q,0,maxcap,maxvex); 47 int tmp=maxcap;//先记录从q点出发到达树的直径的一端的距离 48 maxcap=0;//重置0 49 bfs(maxvex,0,maxcap,maxvex); 50 tmp=min(tmp,maxcap-tmp); 51 printf("%d\n",maxcap-tmp+(sum-maxcap+tmp)*2); 52 } 53 return 0; 54 }