フェイス質問
説明
所与\(N- \)点、\(m個\)自由縁部は、図に削除することができる。(ループフリー)図の側面から、エッジは、図1の二部グラフにQを削除することができます。
入力
第\(1 \)線は、2つの整数含ま\(N- \) 、\(m個\)を、それぞれ、点、エッジ。
第\(2 \ SIM M + 1 \) 各列に2列\(X \) 、\(Y \)は、エッジがあるアタッチメントのポイント表す\(X \) 、\(Y \)を。
出力
エッジの数を表す2つの整数の最初の行は削除することができます。
出力側の昇順で次の行には、番号を削除することができます。
サンプル入力
4 4
1 2
1 3
2 4
3 4
サンプル出力
4
1 2 3 4
ヒント
(\ 10 \%の\)データ、\(N、M <= 10 \)
(40 \%\)\データ\(N、M <= 1000 \)
(\ 70 \%\)データ、\(N、M <= 100000 \)
\(100 \%\)データ、\(N、M <= 2,000,000 \)
問題の解決策
グラフは二部グラフであるかどうかを決定する方法を検討してください:奇数図形リングかどうかを決定するために、使用することができる\(深い\)または(カラー\)を\(染色)メンテナンス。
それを図が想定される\(K \)奇数環は、新しいエッジは、図1の二部グラフであるように、削除されるべきである。これらは、必要があり(\ K)を\奇数リングを破壊または削除、これは(Kを\ \ )エッジ奇数は環のいずれかを削除します。
すなわち、削除することができ、すべての奇数環上縁の原画像を仮定すると、です。
しかし、問題は、このリングは、それが偶数であることが奇数である、このエッジの後に環を形成する2奇数リング2つの奇数側の合計削除されたリングのエッジが存在すると仮定すると、ありますか?
答えがあっても2つの奇数リングとマイナスのこのリング和の原点に等しい点の総数とされている\(2 \) 、偶数です。
その後、我々は設定されている各辺ました\(NUM \) 、奇数リングは、このエッジの後がある場合、それ\([I] NUM ++ \) 、および、この辺で最後に見て\(numは\)かどうかうまく奇数環の総数に等しいです。
しかし、この辺はわかります\(\色{赤} {\ mathrm {WA}} \) 、なぜ?
図のような状況を考慮してください。
これらの中で、赤色側であっても環で青色側に取り付けられた奇妙なリングに取り付けられています。
あなただけの理論に従えば、これらのエッジは、すべて削除することができる必要があります:\((1,2)\)、\ ((1,3)\)、\ ((2,3)\) 。
しかし、我々は、我々はエッジ削除するとことがわかった\((2,3)\) 、新しい計画が奇数リング(で\(1 \ longrightarrow2 \ longrightarrow4 \ longrightarrow5 \ longrightarrow3 \ longrightarrow1 \) )。
問題は、両方の奇数リングのエッジ(する奇数リングポイントを設けたとき、ということである)(\を\次に、\(\)が奇数である)、及び結合リングは、(する摩擦リングポイントを設けたときに(Bを\ \ )、次いで\(B \)が偶数である)、奇数と偶数の環はこのエッジの後に削除されたシクロアルキル環を形成し、そしてポイントがする(A + B-2 \)を\、それが奇数の環です。
だから、両方のリング上の偶数と奇数のリング上のエッジが、我々はそれに投票することができないとき。
だから我々は、各エッジを設定する必要があります\(フラグ\)その上で判断をしても、リングではありません。
奇数リングせずに特別な文を覚えて、その後、縁があることができるいずれかを削除します。
次のように最後のコードは次のとおりです。
#include<bits/stdc++.h>
#define N 4000010
using namespace std;
int n,m,ans[N];
int cnt,tot,idx,top,head[N],nxt[N],to[N],id[N];
int col[N],num[N],st[N],dfn[N];
bool flag[N],vis[N],use[N];
void adde(int u,int v,int ii)
{
to[++cnt]=v;
id[cnt]=ii;//id即这条边对应的是输入中的第几条
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int u,int fa)
{
dfn[u]=++idx;
for(int i=head[u];i;i=nxt[i])
{
if(dfn[to[i]]>dfn[u]||to[i]==fa)
continue;
if(col[to[i]]!=-1)//如果已经访问过
{
if(col[to[i]]==col[u])//颜色相等即奇环
{
tot++;
num[id[i]]++;
for(int j=top;j&&to[st[j]]!=to[i];j--)//循环枚举环上的每一个点
num[id[st[j]]]++;//记录num
}
else
{//颜色不等即偶环
for(int j=top;j&&to[st[j]]!=to[i];j--)
flag[id[st[j]]]=true;//标记flag
}
continue;
}
col[to[i]]=col[u]^1;//染色
st[++top]=i;//丢进stack
dfs(to[i],u);
st[top--]=0;//记得弹出来
}
}
void check(int u)
{
vis[u]=true;
for(int i=head[u];i;i=nxt[i])
{
if(!use[id[i]]&&((!flag[id[i]]&&num[id[i]]==tot)||!tot))//如果这条边还没有记录在答案里(去重),且没有奇环,或者这条边在所有奇环上且不在偶环上
{
use[id[i]]=true;
ans[++ans[0]]=id[i];
}
if(!vis[to[i]])
check(to[i]);
}
}
int main()
{
memset(col,-1,sizeof(col));//每个点的颜色(初始化)
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
adde(u,v,i),adde(v,u,i);//建边
}
for(int i=1;i<=n;i++)
{
if(col[i]==-1)
{
tot=0;
col[i]=0;
dfs(i,-1);
check(i);
}
}
sort(ans+1,ans+ans[0]+1);
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++)
printf("%d ",ans[i]);
return 0;
}