[POJ2942]:円卓の騎士(+尖塔二部グラフ染色)

トピックポータル


件名の説明:

アーサー王は、ラウンドテーブルで開催される会議を騎士満足のいく結果を作ることができ騎士団との会議の議題の間の紛争につながるしないようにするために、それぞれが会議の前に、会議に出席騎士ため、次の要件を持っている必要があります。

  1、2人の騎士直接隣接座っていない嫌い2つの位置。

  2、会議に出席するために騎士の数が議決権の問題は結果を持つことができるようにすることですこれは、奇数でなければなりません。いくつかの騎士がある場合(例えば、他のすべての騎士を嫌っていた騎士のような)すべての会議に出席することができない表示され、世界平和のためのアーサー王は騎士団から彼を拒絶するように強制されます。       

今会議に騎士の与えられた数行く準備ができてN-次い、M(表し憎しみのを2騎士の間では、お互いを嫌い)、少なくともアーサー王の騎士が正常に会うために取り外すことが何頼みますか? 

注意:

  1、憎悪関係は双方向を指定する必要があり、決して憎悪関係は存在しません。

  2それは、ラウンドテーブルであるため、騎士の周りが出席し、それぞれがちょうど持っている必要があります2騎士を。これは、各座席の両側に、彼らは騎士団の騎士を持つようにバインドされています。

  3、騎士は、少なくともがあることを、満たすことができない3人ののみ可能会議騎士。


入力フォーマット:

入力は、いくつかのテストケースが含まれています。二つの整数含有する各々の場合1≤n≤10001≤m≤1000000整数行開始。デジタルnは騎士の数です。のm行は何ナイトライダーた憎悪を記述する。このmは、各行線は、二つの整数含まK1K2をナイトの数つまり、K1およびナイト番号K2(番号迷惑互いにK1およびK2をにて1Nの間)。
入力はn = m = 0で終了します。


出力フォーマット:

各試験のために、整数の出力は、ナイトの数が排出されなければならない意味します。


例:

サンプル入力:

5
1 4
1 5
2 5
3 4
4
0 0

出力例:

2


ソリューション:

複雑な少し、思考の大量。

アーサー王を保持することができます騎士の任意の会議に参加することができるいくつかの会議を、開催に注意してください。

図のように定義されたオリジナルを、構築を検討:今接続されていない接続元の2点は、接続元の2つの点は、現在接続されていません。

この場合、2つの条件は、実際に一緒に座ることができても、プロセスを容易にしているそれらの間のエッジがあります。

彼は奇妙なリングにあった場合にのみあれば、騎士は、会議に参加することができます。

2つの定理を考えます:

  1、奇数の二重丸で連結成分の頂点の一部(すなわち、ビス通信コンポーネントは、奇数サイクルを含んでいた)場合、次にダブル奇数円のコンポーネントを接続している他の頂点。

  図2は、奇数サイクルを含む接続部品の一組あれば、彼は、二部グラフであってはなりません。反対に、これは必要十分条件である、また事実です。

明らか尖塔は、各使用して得られたV-DCCを、次に決定V-DCCがリングに奇数ありません。

この場合には、クロス染色を使用してDFS各側に隣接する2つの辺が奇数の同じカラーリングである場合、逆の色の両側に見つけたとき。

特記事項:この質問は、そうでない場合は、彼らがなり、ユニバーサルヘッダファイルにすることはできませんCE

これらは、CE兄とダウン:

しかし、結果は常に良いです。


コードの時間:

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>//不要万能头!!!
using namespace std;
struct rec
{
	int nxt;
	int to;
}e[1000001];
int head[1001],cnt;
int dfn[1001],low[1001],sta[1001],tot,top;
bool par[1001],vis[1001];
int col[1001];
bool Map[1001][1001];
vector<int> dcc;
void pre_work()//多测不清空,爆零两行泪TAT……
{
	cnt=0;
	tot=0;
	top=0;
	memset(head,0,sizeof(head));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(sta,0,sizeof(sta));
	memset(vis,0,sizeof(vis));
	memset(Map,0,sizeof(Map));
}	
void add(int x,int y)//建边
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
bool dfs(int x,int color)//交叉染色法判奇环
{
	col[x]=color;
	for(int i=head[x];i;i=e[i].nxt)
	{
		if(!par[e[i].to])continue;
		if(col[e[i].to]==color)return 1;
		if(!col[e[i].to]&&dfs(e[i].to,-color))return 1;
	}
	return 0;
}
void color_solve()//将v-DCC转入数组,方便处理
{
	memset(par,0,sizeof(par));
	memset(col,0,sizeof(col));
	for(int i=0;i<dcc.size();i++)
		par[dcc[i]]=1;
	if(dfs(dcc[0],1))
		for(int i=0;i<dcc.size();i++)vis[dcc[i]]=1;
}
void tarjan(int x)//塔尖
{
	dfn[x]=low[x]=++tot;
	sta[++top]=x;
	for(int i=head[x];i;i=e[i].nxt)
	{
		if(!dfn[e[i].to])
		{
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
			if(dfn[x]<=low[e[i].to])//发现v-DCC
			{
				int y;
				dcc.clear();
				do
				{
					y=sta[top--];
					dcc.push_back(y);
				}while(e[i].to!=y);
				dcc.push_back(x);
				color_solve();
			}
		}
		else low[x]=min(low[x],dfn[e[i].to]);
	}
}
int main()
{
	while(1)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		(! - && M n)は、BREAK IF 
		pre_work(); 
		(。; I <= M; INT I = 1 Iが++)用
		{ 
			int型X、Y; 
			scanfの( "%のDの%のD"、およびX&Y); 
			マップ[X ] [Y] =マップ[Y ] [X] = 1; // 仮止めマトリックス堆積図
		} 
		ため(INT I = 1; I <= N; I ++)
			のための(INT J = I 1 +; Jが<= N- ; J ++)
				マップ[I] [J]){追加(I、J);追加(J、I);} IF!//スターチェーンアンチ図は、前項に建てられた
		(のためにI = 1をint型; I <= N-;私は++)
			IF(DFN [I])Tarjan(I);! 
		int型ANS = 0; 
		のため(int型I = 1; I <= N;私は++)//ナイトに参加することができます統計
			であれば(VIS [I]) ++ ANS; 
		のprintf( "%Dの\のN-"、N - ANS); //ナイトの合計数減算
	} 
	戻り0; 
}

 

RP ++

おすすめ

転載: www.cnblogs.com/wzc521/p/11183707.html