题解:P1636 Einstein学画画
为什么有 7000 通过的题目的测试点是错完了的,我也很好奇呢。
下称度数为奇数的点为奇点,度数为偶数且非
首先我们考虑对于一个连通图最少需要几笔画完。
我们每一笔肯定会形成一个路径,这条路径的中间节点(除开头结尾的节点)会被经过两次(进一次,出一次),那么这个节点的度数就会减少
考虑开头、结尾节点。如果开头、结尾节点不一样,那么会单进(或单出),这个节点的度数会减少
所以每次最多让两个节点的度数减少
那么我们此时贪心地猜想每条路径可以把两个奇点变成偶点(如果没有奇点直接删一条欧拉回路就好了,证明详见 OI-WIKI),是不是只需要操作奇点个数除以
事实上这是正确的读者自证不难。证明:
由于图连通,所以每次一定可以找到一条连接两个奇点的路径并删除。然后图会变成一个或多个连通图,对每个连通图继续做即可。
那么删的时候可能会遇到以下情况:
如果对几对奇点操作后,在剩下的奇点中,有一个奇点与其他奇点互不连通(或整个图只有
1 个奇点)。即,有一个子图连通且有奇数个奇点,不合图的性质(一个图只可能有偶数个奇点),即不可能出现。
如果删完所有奇点最后还会剩偶点。
由于只有偶点的图是欧拉图(或者一些互不连通的欧拉图的并),而且对于每一个子连通图肯定有至少一个点被访问过(如果没有,就违反了原图是连通图的题设)。
此时我们可以在经过这个偶点的那条路径上插入一条欧拉回路。由于欧拉回路起终点相同,所以并不会破坏路径的性质;而且欧拉图一定会有一个欧拉回路(证明见 OI-WIKI)。
所以可以做到删完奇点后啥也不剩。
所以我们只要对每个连通子图统计奇点个数再除
注意细节:
-
图不一定连通!!!
-
一个没有奇点的图可能都是偶点,也要走一次;
-
在判定上面那一条的时候注意孤立点不用走。
代码:
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
bool vis[maxn];
int n,m,u,w,v,f[maxn],ans = 0,cnt;
vector<int>e[maxn],tmp[maxn];
void dfs(int u,int&id){
vis[u]=1,tmp[id].push_back(u);
for(auto v:e[u])if(!vis[v])dfs(v,id);
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1;i <= m;i++)
{
scanf("%d%d", &u, &v);
f[v]++;
f[u]++;
e[u].push_back(v),e[v].push_back(u);
}
for(int i=1;i<=n;++i)if(!vis[i])dfs(i,++cnt);
for(int i=1;i<=cnt;++i){
int tmpans=0,can=0;
for(auto x:tmp[i]){if(f[x]&1)++tmpans;if(f[x])can=1;}
tmpans/=2;
if(!tmpans&&can)++tmpans;
ans+=tmpans;
}
printf("%d", ans);
return 0;
}