题目:
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
list<int>edge[10001];
int n;
stack<int>ans;
int num_of_sin() //求奇点的个数,是0,2,还是大于2
{
int ans = 0;
for (int i = 1; i <= n && ans<=2; i++)if (edge[i].size() % 2)ans++;
return ans;
}
bool con() //判断是否为连通图
{
int *p = new int[n + 1];
for (int j = 1; j <= n; j++)p[j] = 0;
queue<int>q;
while (!q.empty())q.pop();
p[1] = 1, q.push(1);
while (!q.empty())
{
int k = q.front();
q.pop();
for (list<int>::iterator it = edge[k].begin(); it != edge[k].end(); it++)if (p[*it] == 0)
{
p[*it] = 1;
q.push(*it);
}
}
for (int j = 1; j <= n; j++)if (p[j] == 0)return false;
return true;
}
bool ok() //判断能不能一笔画
{
if (num_of_sin() > 2 || !con())return false;
if (num_of_sin() == 0)return true;
return edge[1].size() % 2;
}
bool dfs(int s, int deep)
{
if (edge[s].empty())return deep == 0;
int e = *min_element(edge[s].begin(), edge[s].end());
edge[s].remove(e), edge[e].remove(s);
if (dfs(e, deep - 1))
{
ans.push(e);
return true;
}
if (edge[s].empty())
{
edge[s].push_back(e), edge[e].push_back(s);
return false;
}
int t = *min_element(edge[s].begin(), edge[s].end());
edge[s].push_back(e), edge[e].push_back(s);
e = t;
edge[s].remove(e), edge[e].remove(s);
if (dfs(e, deep - 1))
{
ans.push(e);
return true;
}
edge[s].push_back(e), edge[e].push_back(s);
return false;
}
int main()
{
int m, a, b, s = 1;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)edge[i].clear();
for (int i = 0; i < m; i++)
{
scanf("%d%d", &a, &b);
edge[a].push_back(b), edge[b].push_back(a);
}
if (!ok())
{
cout << -1;
return 0;
}
while (!ans.empty())ans.pop();
dfs(1, m);
cout << 1;
while (!ans.empty())
{
printf(" %d", ans.top());
ans.pop();
}
return 0;
}
结果:超时,得分70(满分100)
思路:
定理一:对于无向图,奇点的个数一定是偶数,如果奇点个数超过2,那么无法一笔画,如果奇点个数为2或者0,只要图是连通的就可以一笔画,不是连通的图自然无法一笔画。
定理二:对于连通图,如果奇点个数为2,那么2个奇点可以任选1个作为起点,其他点不能作为起点,如果奇点个数为0,那么任何一个点都可以作为起点。
定理三:对于一个可以一笔画的图,起点集由定理二确定,那么去掉任何一条包含某个起点的边,得到的子图只要是连通的就仍然可以一笔画。换句话说,在一笔画的过程中,只要始终保持所有的边是连通的即可。