1 条题解
-
0
题意
有个 n 个顶点的凸多边形,里面还有 m 条不相交的对角线,现在给出这 n 条边和 m 条对角线,求出这个凸多边形的一条哈密顿路径。
分析
因为内部的对角线都不相交,所以至少有一个顶点只有两条边,即它唯一确定了两条边,从集合中删除这两条边,再给两个相邻顶点连一条边(如果已经有,就不用加了),并且给这条边标记,因为它必不可能是边。 接下就变成了 n-1 个顶点的凸多边形,且内部对角线依旧不相交,然后重复这些步骤
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<functional> using namespace std; typedef pair<int,int> P; const int N = 50000+5; vector<int>e[N]; // 存储边集 vector<int>vt[N]; // 被标记过的边集 vector<int>ans[N]; // ans[i][0] 和 ans[i][1] 分别代表凸多边形的顶点 i 相邻的两个顶点,即两条边 int n,m; int vis[N]; int set[N]; void dfs(int num,int tot,int pre) { if(tot==n+1) return; set[tot]=num; int a=ans[num][0]; int b=ans[num][1]; if(a==pre) dfs(b,tot+1,num); else dfs(a,tot+1,num); } int main() { int T; scanf("%d",&T); while(T--) { memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) e[i].clear(),ans[i].clear(),vt[i].clear(); for(int i=1;i<=n+m;i++) { int u,v; scanf("%d%d",&u,&v); e[u].push_back(v); e[v].push_back(u); } priority_queue<P,vector<P>,greater<P> >que; //按照顶点边和对角线总数量从小到大排序 for(int i=1;i<=n;i++) { que.push(P(e[i].size(),i)); } while(!que.empty()) { P p=que.top(); que.pop(); int v=p.second; if(vis[v]) continue; vis[v]=1; if(p.first==1) //队列首顶点的边数为 1 ,则这是凸多边形的最后一条边; { int u=e[v][0]; ans[u].push_back(v); ans[v].push_back(u); break; } int a=e[v][0]; int b=e[v][1]; vector<int>::iterator it; for(it=e[a].begin();it!=e[a].end();it++) //从边集中删除 边 a-v { if(*it==v) { e[a].erase(it); break; } } for(it=e[b].begin();it!=e[b].end();it++) //从边集中删除 边 b-v { if(*it==v) { e[b].erase(it); break; } } int has=0; for(int i=0;i<e[a].size();i++) //判断边集中有没有 a-b,没有就加进去 { int k=e[a][i]; if(k==b) { has=1; break; } } if(has==0) { e[a].push_back(b); e[b].push_back(a); } int ok=1; for(it=vt[v].begin();it!=vt[v].end();it++) //如果标记边集中没有 a-v,则其是原边之一 { if(*it==a) { ok=0; break; } } if(ok) ans[v].push_back(a),ans[a].push_back(v); ok=1; for(it=vt[v].begin();it!=vt[v].end();it++) //如果标记边集中没有 b-v,则其是原边之一 { if(*it==b) { ok=0; break; } } if(ok) ans[v].push_back(b),ans[b].push_back(v); int numa=e[a].size(); //更新顶点 a 和 b 的边数并重新压进队列 int numb=e[b].size(); que.push(P(numa,a)); que.push(P(numb,b)); vt[a].push_back(b); //给边 a-b 标记 vt[b].push_back(a); } set[1]=1; dfs(min(ans[1][0],ans[1][1]),2,1); // 统计顶点序列 putchar('1'); for(int i=2;i<=n;i++) printf(" %d",set[i]); puts(""); } }
- 1
信息
- ID
- 430
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者