这个题当时也没做出来 赛后听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 ",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 ",g[i][len-1]); } return 0; }