这个题当时也没做出来 赛后听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;
}