您的位置:首页 > 产品设计 > UI/UE

【2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest H】【观察找规律 脑洞 构造】Tourist Guide 关键点作端点最多路径

2015-11-08 12:41 507 查看
H. Tourist Guide

time limit per test
2 seconds

memory limit per test
512 megabytes

input
standard input

output
standard output

It is not that easy to create a tourist guide as one might expect. A good tourist guide should properly distribute flow of tourists across the country and maximize the revenue stream
from the tourism. This is why there is a number of conditions to be met before a guide may be declared as an official tourist guide and approved by Ministry of Tourism.
Ministry of Tourism has created a list of k remarkable
cities out of n cities in the country. Basically, it means that in order to conform
to strict regulations and to be approved by the ministry a tourist guide should be represented as a set of routes between remarkable cities so that the following conditions are met:

the first and the last city of every route are distinct remarkable cities,

each remarkable city can be an endpoint of at most one route,

there is no pair of routes which share a road.
Please note that a route may pass through a remarkable city. Revenue stream from the tourism highly depends on a number of routes included in a tourist guide so the task is to find
out a set of routes conforming the rules of a tourist guide with a maximum number of routes included.

Input
The first line contains three integer numbers n,  m,  k (1 ≤ n ≤ 50000,  0 ≤ m ≤ 50000,  1 ≤ k ≤ n) —
the number of cities in the country, the number of roads in the country and the number of remarkable cities correspondingly.
Each of the following m lines
contains two integer numbers ai and bi (1 ≤ ai, bi ≤ n) —
meaning that cities ai and bi are
connected by a bidirectional road. It is guaranteed that ai and bi are
distinct numbers and there is no more than one road between a pair of cities.
The last line contains k distinct
integer numbers — a list of remarkable cities. All cities are numbered from 1 to n.

Output
The first line of the output should contain c —
the number of routes in a tourist guide. The following c lines should contain
one tourist route each. Every route should be printed in a form of "t v1 v2 ... vt + 1",
where t is a number of roads in a route and v1,  v2, ..., vt + 1 —
cities listed in the order they are visited on the route.
If there are multiple answers print any of them.

Sample test(s)

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


output
2
2 1 2 3
2 4 5 6


input
4 3 4
1 2
1 3
1 4
1 2 3 4


output
2
1 1 2
2 3 1 4


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<vector>
#include<map>
#include<algorithm>
#define ls o<<1
#define rs o<<1|1
using namespace std;
typedef long long LL;
const int N=5e4+10;
bool e
;
int f
,com
,head
;
vector<int>a
;//a[]表示原图
vector<int>b
;//b[]表示记录答案的路径
int n,m,k,x,y;
int ans;
int find(int x)
{
if(f[x]==x)return f[x];
f[x]=find(f[x]);
return f[x];
}
void dfs(int x)
{
e[x]=1;
int st=0;
for(int i=a[x].size()-1;~i;--i)
{
int y=a[x][i];
if(e[y])continue;
dfs(y);
if(com[y])
{
if(st==0)
{
st=com[y];
b[st].push_back(x);
}
else
{
int ed=com[y];
for(int j=b[ed].size()-1;~j;--j)b[st].push_back(b[ed][j]);
head[++ans]=st;
st=0;
}
}
}
if(st==0)
{
if(com[x])b[x].push_back(x);
}
else//st exist
{
if(com[x])
{
head[++ans]=st;
com[x]=0;
}
else com[x]=st;
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
for(int i=1;i<=n;i++)
{
e[i]=0;
f[i]=i;
a[i].clear();
b[i].clear();
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
int fx=find(x);
int fy=find(y);
if(fx==fy)continue;
f[fy]=fx;
a[x].push_back(y);
a[y].push_back(x);
}
while(k--)
{
scanf("%d",&x);
com[x]=x;
}
ans=0;
for(int i=1;i<=n;i++)if(e[i]==0)dfs(i);
printf("%d\n",ans);
for(int i=1;i<=ans;i++)
{
int x=head[i];
int g=b[x].size();
printf("%d ",g-1);
for(int j=0;j<g;j++)printf("%d ",b[x][j]);
puts("");
}
}
}
/*
【trick&&吐槽】
题目难下手?
构造样例多观察。
找出结论再思考。
HDU只有我一个人做了出来啦啦啦~

【题意】
有n(50000)个点,m(50000)条边,其中有k(1<=k<=n)个点是特殊点。
我们想要在特殊点之间画路径,要求:
1,每个特殊点最多是一条路径的端点
2,原图中的每条边最多只被画一次
3,使得路径数尽可能多。

【类型】
脑洞,构造

【分析】
这题乍一想确实是很难想,然而——我们还是有迹可循的。
1[观察],数据规模如此之大,必须用O(n)或者O(nlogn)之级别的算法
2[猜想],我们经过对样例的观察,以及思考,发现:对于一个包含w个点联通块,可以画出的路径数一定是[w/2]
首先画一画找不到反例,于是我们顺着这个思路往下展开——
因为树是最基本的联通块,而且不改变刚才那个猜想,且很多问题在图上很难思考。
所以我们不妨把这个图生成任意一个生成树,然后去构造路径。

3[思考],在树上怎么思考?
一个比较容易的思考方式,是沿子树展开。
首先我们发现,从一棵子树的内部,最多向外展开一条路径。
于是我们对于这棵子树,对于根节点下方每个有出路径的子节点。
A,如果(出路径数+根节点的重要度)为偶数,每个pair我们就合并再一起。没有外延展。
B,如果(出路径数+根节点的重要度)为奇数,每个pair我们就合并再一起。然后多出一个外展。

我们发现这种构造,不仅证明了猜想的正确性,而且这道题就可以AC啦。

==================================================================================
剩下的最后一个问题——如何实现[3]?
我们如果用b[]来记录路径,因为每个点可能被push_back进去多次。所以我们是不太容易设定后继的。
我们不妨把所有出路径的子节点,连向父节点。
然后遇到要合并的pair,我们就把其中第二个路径反一下再连起来。
这样最后就能AC啦!

【时间复杂度&&优化】
O(n)

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息