扫雪系列I
题目
题解
思路
这是一道树的题目。我们先来分析一下样例:
总共5个结点,1是根节点。
结点1与结点2建立了一条长度为1的边。
结点2与结点3建立了一条长度为1的边。
结点3与结点5建立了一条长度为1的边。
结点3与结点4建立了一条长度为1的边。
5是怎么得来的呢?我们用一个路线来表示:1->2,2->3,3->4,4->3,3->5,总共用的燃料数量是:1+1+1+1+1=5。但用这样的方法去写程序的话很难写,那还有什么方法吗?当然有,我们先把所有边的值都加起来,记作sum。因为模拟时某一条边有可能会重复走,我们就假设每一条边都重复走了,所以sum要乘上2。因为我们假设每一条边都重复走了,那肯定要减与根节点离的最远的叶子结点到根节点的路径的边的和。例如在样例中,跟根节点离的最远的叶子结点到根节点的路径的边的和是3(1->2->3->5(或4)),用边*2-3,(1+1+1+1)*2-3=5。我们只需要用dfs来算出与根节点离的最远的叶子结点是多少,顺便求出每个结点到根节点的距离(即深度)就可以算出最总答案了。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node //结构体
{
int ans,len; //ans是与当前结点相连的结点是什么,len是与当前结点相连的结点的边的长度
};
int n,a[100001],k,cnt=0;
vector<node> adj[100001]; //我用的是vector数组
void dfs(int u,int fa,int sum) //u是当前结点,fa是u的父结点,sum是u与根节点的距离
{
cnt=max(cnt,sum);
for(int i=0;i<adj[u].size();i++)
{
int t=adj[u][i].ans;
if(t==fa)continue;
dfs(t,u,sum+adj[u][i].len); //dfs
}
}
signed main()
{
cin>>n>>k;
int num=0;
for(int i=1;i<n;i++) //输入
{
int c,d,e;
cin>>c>>d>>e;
num+=e;
adj[c].push_back({d,e}); //双向建边
adj[d].push_back({c,e});
}
dfs(k,0,0); //递归
cout<<2*num-cnt; //输出
return 0;
}
结果......
AC了!!!!!!!
扫雪系列II
题解
思路
这一题更上一题差不多,只不过将只有一辆铲雪车及一名司机改成了只有两辆铲雪车及两名司机而已。我们可以先找到这棵树的直径,然后把所有的街道的和乘以2减去树直径就好了。其实就相当与把一辆车走的还要折返来的最长的那一段路让第二辆车去走。我们来举两个例子:
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node
{
int ans,len;
};
int n,a[100001],k,cnt=0,w;
vector<node> adj[100001];
void dfs(int u,int fa,int sum)
{
if(cnt<sum)
{
cnt=sum;
w=u;
}
for(int i=0;i<adj[u].size();i++)
{
int t=adj[u][i].ans;
if(t==fa)continue;
dfs(t,u,sum+adj[u][i].len);
}
}
signed main()
{
cin>>n>>k;
int num=0;
for(int i=1;i<n;i++)
{
int c,d,e;
cin>>c>>d>>e;
num+=e;
adj[c].push_back({d,e});
adj[d].push_back({c,e});
}
dfs(k,0,0);
cnt=0;
dfs(w,0,0);
cout<<2*num-cnt;
return 0;
}