Codeforces 589H Tourist Guide (NEERC 2015 H题)

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



这个题当时也没做出来 赛后听zb大爷讲过写出来了

首先orz zb srm 岛娘 今天沈阳regional取的亚军


题目大意是 有一个图 有一些点是带标记的

让你求最多的路径 要求

1.路径上的起点和终点都是带标记的

2.每个带标记的点只能作为最多一条路径的端点

3.两条路径不能有公共边


转化到树上做

对于每个子树 、

如果恰有偶数个标记的点 一定可以在子树内相互连接到达

如果有奇数个标记的点 就把多的那个点尝试通过子树的父亲连接


看代码很简单 就是挺难想的。。

dfs返回以u为根的子树中最后一个没被匹配的带标记的点

如果没有 返回-1

如果有 尝试与其他子树的最后一个没被匹配的点作为路径

#include<bits/stdc++.h>
using namespace std;
const int lim=50011;
int m,tn,q,n;

struct self
{
    int x,y,nxt;
}s[lim<<1];

int fa[lim];
int flag[lim];
int x,y;
int remark[lim];
int fst[lim];
vector<int>g[lim];
int ans;
void add(int x,int y)
{
    n++;
    s[n].x=x;
    s[n].y=y;
    s[n].nxt=fst[x];
    fst[x]=n;
}
void makel(int ans,int f,int t)
{
    for(int e=f;e!=t;e=fa[e])
        g[ans].push_back(e);
    g[ans].push_back(t);
}
void maker(int ans,int t,int f)
{
    if(t==f)
        return;
    maker(ans,fa[t],f);
    g[ans].push_back(t);
}
void make(int l,int root)
{
    ans++;
    makel(ans,l,root);
}
void make(int l,int root,int r)
{
    ans++;
    makel(ans,l,root);
    maker(ans,r,root);
}
int dfs(int u,int ff)
{
    fa[u]=ff;
    flag[u]=1;
    int f1=-1,f2=-1;
    for(int e=fst[u];e!=-1;e=s[e].nxt)
    {
        int v=s[e].y;
        if(!flag[v])
        {
            if(f1==-1)
                f1=dfs(v,u);
            else
                f2=dfs(v,u);
            if(f1!=-1 && f2!=-1)
            {
                make(f1,u,f2);
                f1=f2=-1;
            }
        }
    }
    if(remark[u])
    {
        if(f1!=-1)
        {
            make(f1,u);
            return -1;
        }
        else
            return u;
    }
    else
        if(f1!=-1)
            return f1;
        else
            return -1;
}

int main()
{
    scanf("%d%d%d",&m,&tn,&q);
    memset(fst,-1,sizeof(fst));
    n=0;
    for(int i=1;i<=tn;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&x);
        remark[x]=1;
    }
    for(int i=1;i<=m;i++)
        if(!flag[i])
            dfs(i,-1);
    printf("%d\n",ans);
    for(int i=1;i<=ans;i++)
    {
        int len=g[i].size();
        printf("%d ",len-1);
        for(int j=0;j<len-1;j++)
            printf("%d ",g[i][j]);
        printf("%d\n",g[i][len-1]);
    }
    return 0;
}



 

转载于:https://www.cnblogs.com/abgnwl/p/6550334.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值