bzoj 2657: [Zjoi2012]旅游(journey) (map建图+树的直径)

2657: [Zjoi2012]旅游(journey)

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 889  Solved: 558
[ Submit][ Status][ Discuss]

Description

     到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~

    经过一番抉择,两人决定将T国作为他们的目的地。T国的国土可以用一个凸N边形来表示,N个顶点表示N个入境/出境口。T国包含N-2个城市,每个城市都是顶点均为N边形顶点的三角形(换而言之,城市组成了关于T国的一个三角剖分)。两人的旅游路线可以看做是连接N个顶点中不相邻两点的线段

   为了能够买到最好的纪念品,小白希望旅游路线上经过的城市尽量多。作为小蓝的好友,你能帮帮小蓝吗?

Input

 每个输入文件中仅包含一个测试数据。
第一行包含两个由空格隔开的正整数N,N的含义如题目所述。
     接下来有N-2行,每行包含三个整数 p,q,r,表示该城市三角形的三个顶点的编号(T国的N个顶点按顺时间方向从1至n编号)。

Output

      输出文件共包含1行,表示最多经过的城市数目。( 一个城市被当做经过当且仅当其与线路有至少两个公共点)

Sample Input

6
1 2 4
2 3 4
1 4 5
1 5 6

Sample Output

4

HINT

4<=N<=200000

Source

[ Submit][ Status][ Discuss]



题解:map建图+树的直径

将每个三角形看做一个点,将有边相邻的点之间连边,然后求树上的最长链,即树的直径。

这样为什么是对的呢?我们是要选择两个点,求这之间经过的三角形的个数,因为是凸多边形,所以如果两个能连边,那么一定有方式让连线与三角形有至少两个公共点。

画画图就应该明白了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#define N 1000000
#define pa pair<int,int>
using namespace std;
int tot,n,m,point[N],next[N],v[N],f[N],g[N],ans;
map<pa,int> mp;
void add(int x,int y)
{
	tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
	tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
//	cout<<x<<" "<<y<<endl;
}
void dfs(int x,int fa)
{
	int l=0,r=0; f[x]=1; g[x]=1;
	for (int i=point[x];i;i=next[i])
	 if (v[i]!=fa){
	 	dfs(v[i],x);
	 	int t=f[v[i]]+1;
	 	if (t>f[x]) g[x]=f[x],f[x]=t;
	 	else if (t>g[x]) g[x]=t;
	 }
	ans=max(ans,f[x]+g[x]-1);
}
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n-2;i++) {
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		if (y>x) swap(y,x);
		if (z>x) swap(z,x);
		if (z>y) swap(y,z);
		pa a=make_pair(x,y);
		if (mp[a])  add(mp[a],i);
		else mp[a]=i;
		a=make_pair(y,z);
		if (mp[a]) add(mp[a],i);
		else mp[a]=i;
		a=make_pair(x,z);
		if (mp[a]) add(mp[a],i);
		else mp[a]=i;
	}
	dfs(1,0);
	printf("%d",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值