题解 P3022 【[USACO11OPEN]奇数度Odd degrees】
3493441984zz
2019-02-02 10:53:09
# 动态规划?~~(我不会)~~
### 直接找规律搜索!!!
------------
# 题外话:
可能本人的思路跟楼下们相同,反正我看不懂$qwq$(本人很菜)
所以我就自己琢磨,然后希望能表述清楚,我做完后偷瞄了楼下$dalao$们的代码,好像差不多$qwq$~~(尴尬)~~
------------
# 思路:
这道题目不难,我也不知道怎么用$dp$做$qwq$
### 先说做法(至于为什么下文会提到):
我们搜索每一个没访问过的点,对于搜索进来的这条边,我们不管它,让它继续搜索下去,直到访问了每个节点后,统计度数,如果现在是偶数度的话,我们就连上最开始搜索进来的边,保证当前点是奇数度
### 知道你们现在还迷糊$qwq$,来人啊,上性质!!!
于是我门开始找性质:
$1$、只需要一条边的变化,就能从奇数度与偶数度相互转换(废话)
也就是说一个点如果多一条边或者少一条边,就能从奇数度变为偶数度,或者从偶数度变为奇数度(感觉我在侮辱你们智商)
### 那么,来人啊!上样例!!!
$\quad1-2$
$\,\,\quad$\$\quad $/
$\quad\quad3-4$
我们从$1$号出发,搜索到$2$节点,继续搜索到$3$号节点,$3$号节点不能去$1$号,因为$1$被访问过了,所以到$4$去,而$4$号节点没有能走的地方了,于是我们统计$4$号点的度数为$0$(不算$3-4$这条搜索进来的边),那么现在$4$号节点就是偶数度,那么我们只能通过连上搜索进来的这条边$3-4$来保证$4$号点是奇数度
于是保留$3-4$这条边,那么返回到$3$节点,$3$节点相邻的$1,2,4$都被访问过了,于是统计度数,因为不算$2-3$这条边,所以$3$的度数为$1$,因为与$4$连了一条边,而现在是奇数度,所以我们不能连上$2-3$这条边,不然就多此一举的从奇数度变为了偶数度
那么又返回到$2$节点,与之相邻的点也都被访问过了,那么统计度数,由于$1-2$这条搜索进来的边先不管,而$2-3$这条边不连,所以$2$号点的度数为$0$,那么我们就必须连上$1-2$这条搜索进来的边来保证当前点是奇数度
于是保留$1-2$这条边,返回到$1$节点,发现没有与之相邻没访问过的点了,那么统计度数为$1$,因为与$2$连了边,那么也就方案成立了,所有点的度数都是奇数度啦
所以我们就连了$1-2$,$3-4$保证所有点是奇数度
### 等等??样例输出不是这样啊??
不是有苏卿念$dalao$提供的$SPJ$嘛
那么样例输出是怎么来的呢??
其实是访问的顺序不一样导致的,那就再模拟一遍吧$qwq$
$\quad1-2$
$\,\,\quad$\$\quad $/
$\quad\quad3-4$
我们还是从$1$号点开始搜索,这次我们不先去$2$号点,而是去$3$号点,那么到了$3$号点后,我们随便往哪走,就先往$2$走吧,到了$2$号点后,发现不能走了,并且度数为$0$,那么就必须连上$3-2$这条边,返回到$3$节点,搜索到$4$号点,发现不能走了,于是统计度数为$0$,于是必须连上$3-4$这条边,返回到$3$节点后,发现不能走了,统计度数为$2$,那么就必须连上$1-3$,保证当前点是奇数度,那么返回到$1$节点,统计度数为$1$,于是完美结束
那么保留的边就是$1-3,2-3,3-4$啦
**记得连边连双向边**
#### 最后到了美滋滋的代码时间~~~
~~~cpp
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 50007
#define M 100007
using namespace std;
struct Edge
{
int to,nxt,id;
}edge[M<<1];
int n,m,cnt;
int head[N],ans[M];
bool vis[N];
void Add(int u,int v,int id)
{
edge[++cnt]=(Edge){v,head[u],id};
head[u]=cnt;
}
bool Dfs(int u)
{
vis[u]=1;
int du=0;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(vis[v])
continue;
if(Dfs(v))
{
++du;
ans[++cnt]=edge[i].id;
}
}
if(du%2==0)
return 1;
else
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
Add(u,v,i);
Add(v,u,i);
}
cnt=0;
for(int i=1;i<=n;++i)
if(!vis[i])
if(Dfs(i))
{
printf("-1");
return 0;
}
sort(ans+1,ans+1+cnt);
printf("%d\n",cnt);
for(int i=1;i<=cnt;++i)
printf("%d\n",ans[i]);
}
~~~