列表

详情


NC20204. [JSOI2013]旅行时的困惑

描述

Waldives 有 N 个小岛。目前的交通系统中包含 N-1 条快艇专线,每条快艇专线连接两个岛。这 N-1条快艇专线恰好形成了一棵树。  
由于特殊的原因,所有N-1条快艇专线都是单向的。这导致了很多岛屿之间不能相互到达。因此,Waldives 政府希望新建一些公交线路,使得建设完毕后, 任意两个小岛都可以互相到达。为了节约开支,政府希望建设最少的公交线路。  
同时,出于规划考虑,每一条公交线路都有如下的要求:  
1、每一条交通线路包含若干条连续的快艇专线,你可以认为一条公交线路 对应树上的一条路径,而其所包含的若干快艇专线则对应树上被这条路 径所覆盖的树边(也就是之前已经存在的某个快艇专线);
2、显然一条交通线路只能覆盖树上任意一条边至多一次;
3、公交线路中所包含的每一个快艇专线都是有方向的,并且与其所覆盖的树边的方向相反;
4、不同的公交线路可以覆盖树上相同的点或者相同的边。
Waldives 的 N 个岛屿分别从 0 到 N-1 编号。现在给出 Waldives 已有的快艇专线信息,请计算最少所需要新建的交通线路的数量。

输入描述

第一行包含一个整数 N。
接下来N-1行,每行包含两个整数 x,y。
表示存在一条从岛屿 x开往岛屿y的快艇专线。
N ≤ 100000

输出描述

输出一行一个整数,表示需要建设的最少的交通线路数量。

示例1

输入:

4
0 1
1 2
1 3

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 32ms, 内存消耗: 5472K, 提交时间: 2022-12-30 10:17:05

#include<iostream>
#include<cstdio>
#include<cmath>
const int maxn=1e5+7;
using namespace std;
int n,x,y,cnt,ans;
int f[maxn],ls[maxn];
struct edge
{
    int y,op,next;
}g[maxn*2];
void add(int x,int y)
{
    g[++cnt]=(edge){y,1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,ls[y]};
    ls[y]=cnt;
}
void dfs(int x,int fa,int op)
{
    int num1=0,num2=0;
    for(int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if(y==fa) continue;
        dfs(y,x,g[i].op);
        if(!g[i].op) num1+=max(f[y],1);
        else num2+=max(f[y],1);
    }
    if(num1>num2)
    {
        ans+=num2;
        if(op) ans+=num1-num2;
        else f[x]=num1-num2;
    }
    else
    {
        ans+=num1;
        if(op) f[x]=num2-num1;
        else ans+=num2-num1;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        x++,y++;
        add(x,y);
    }
    dfs(1,0,0);
    ans+=f[1];
    printf("%d\n",ans);
}

C++(clang++ 11.0.1) 解法, 执行用时: 79ms, 内存消耗: 5540K, 提交时间: 2023-07-29 17:41:15

#include<bits/stdc++.h>
using namespace std;
int n,x,y,tot,a[100005],b[100005],ans;
struct edge
{
	int to;
	int next;
	int head;
	int signal;
}edges[100005<<1];
void add(int x,int y,int opt)
{
	tot++;
	edges[tot].to=y;
	edges[tot].next=edges[x].head;
	edges[x].head=tot;
	edges[tot].signal=opt;
}
void dfs(int x,int fa)
{
	for(int i=edges[x].head;i;i=edges[i].next)
	{
		int v=edges[i].to;
		if(v==fa) 
		{
			continue;
		}
		dfs(v,x);
		if(edges[i].signal)//看能传递哪一部分,另外一部分计入答案
		{
			ans+=a[v];
			b[x]+=max(b[v],1);
		}
		else
		{
			ans+=b[v];
			a[x]+=max(a[v],1);
		}
	}
	int t=min(a[x],b[x]);//优先在内部连边
	a[x]-=t;
	b[x]-=t;
	ans+=t;
}
int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		cin>>x>>y;
		add(x+1,y+1,1);
		add(y+1,x+1,0);
	}
	dfs(1,0);
	cout<<ans+max(a[1],b[1]);
	return 0;
}

上一题