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

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[N];
int f[N],com[N],head[N];
vector<int>a[N];//a[]表示原图
vector<int>b[N];//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)

*/


你可能感兴趣的:(ACM,ICPC,codeforces,构造,脑洞)