ZJOI2012 旅游 树的直径+建图

版权声明:本文为DyingShu原创文章,转载请注明出处哦。 https://blog.csdn.net/DyingShu/article/details/82952182

传送门

这题神了。。。

题意:在凸多边形中,画一条两个不相邻顶点之间的线段,使经过的三角形个数最多。

题解:

对于两个有公共边的三角形,可以发现若有一条直线穿过某个三角形并从公共边出去,则一定会选中两个三角形(显然)。而如果直线穿过的是另外两条边,就会和另外两条边外面的三角形连在一起。
所以朝着有公共边的两个三角形连一条边。不难发现建出来的图是一棵树,而直线是不能分叉的,所以问题就转化为求这棵树的直径了。

有点蒙蔽,不过感觉好正确的样子

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 200001;

int fir[MAXN], nxt[MAXN << 1], to[MAXN << 1], cnt;
int Begin, End, dis[MAXN];

struct Triangle{
	int x, y, z;
}Tri[MAXN];

struct E{
	int a, b, num;
	inline bool operator < (const E &e) const{
		if(a == e.a) return b < e.b;
		return a < e.a;
	}
	inline bool operator == (const E &e) const{
		return (a == e.a && b == e.b);
	}
}Edge[MAXN << 2];
int tot;

inline int read(){
	int k = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
	return k * f;
}

inline void add_edge(int a, int b){
	to[cnt] = b;
	nxt[cnt] = fir[a];
	fir[a] = cnt++;
}

void dfs1(int u, int fa){
	if(dis[u] > dis[Begin]) Begin = u;
	for(int i = fir[u]; i != -1; i = nxt[i]){
		int v = to[i];
		if(v == fa) continue;
		dis[v] = dis[u] + 1;
		dfs1(v, u);
	}
}

void dfs2(int u, int fa){
	if(dis[u] > dis[End]) End = u;
	for(int i = fir[u]; i != -1; i = nxt[i]){
		int v = to[i];
		if(v == fa) continue;
		dis[v] = dis[u] + 1;
		dfs2(v, u);
	}
}

int main(){
	freopen("in.txt", "r", stdin);
	memset(fir, -1, sizeof(fir));
	int n = read() - 2;
	for(int i = 1; i <= n; i++){
		int a = read(), b = read(), c = read();
		if(a > c){
			swap(a, c);
		}		
		if(a > b){
			swap(a, b);
		}
		if(b > c){
			swap(b, c);
		}
		Tri[i].x = a, Tri[i].y = b, Tri[i].z = c;
		Edge[++tot] = (E){a, b, i};
		Edge[++tot] = (E){b, c, i};
		Edge[++tot] = (E){a, c, i};
	}
	
	sort(Edge + 1, Edge + tot + 1);
//	for(int i = 1; i <= tot; i++){
//		printf("%d %d %d\n", Edge[i].a, Edge[i].b, Edge[i].num);
//	}
	for(int i = 1; i < tot; i++){
		if(Edge[i] == Edge[i + 1]){
			add_edge(Edge[i].num, Edge[i + 1].num);
			add_edge(Edge[i + 1].num, Edge[i].num);
		}
	}
	
	if(Edge[1] == Edge[n]){
		add_edge(Edge[1].num, Edge[n].num);
		add_edge(Edge[n].num, Edge[1].num);
	}
	
//	printf("cnt = %d\n", cnt);
	int Ans = 0;
	
	memset(dis, 0, sizeof(dis));
	dfs1(1, 0);
	memset(dis, 0, sizeof(dis));
//	printf("Begin = %d\n", Begin);
	dfs2(Begin, 0);
//	printf("End = %d\n", End);
	Ans = dis[End];
	
	printf("%d", Ans + 1);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/DyingShu/article/details/82952182