[HDU6403]: Card Game (ДФС + DP + дерево кольцо)

тема Портал


Название Описание

Она по - прежнему на месте , я не знаю , не знаю.
Распространенный некоторые карты на столе, это игра , она , как правило , очень игривая. Теперь карты до сих пор, она не со мной. Подсознательно, я открыл карту, было отозвано играть в карты в течение этого времени.
передняя и задняя часть и каждой карты есть номер, каждый раз , когда я положил карты , как я хочу на столе, и некоторые из которых она сосала карты переворачивается, и , наконец , составляет все номера на рабочем столе Они разные.
Я посмотрел на себя невольно открыл карту, вдруг вспомнила несколько раз , прежде чем она позволила мне помочь ей рассчитать минимально необходимые для достижения целевого числа флипа минимума, и минимальное количества оборотных программ для достижения своих целей.
(Два метода считается одинаковым , если и только если тот же самый набору из двух способов нужно перевернуть карту) ,
если я ставлю процесс решения письменных процедуры , посланной ей, она позднее время , чтобы играть в этой игре будет больше симпатии некоторых?


Формат ввода

Каждая контрольная точка несколько наборов тестовых данных.
Первая строка имеет положительное целое число , а Т представляет собой число наборов данных.
Далее, для каждого набора данных, первая строка есть целое положительное число N, число карт на столе , на фиг.
Тогда есть N строк двух целых чисел х, у, обе стороны , представленные в х, у карты, а также текущее число восход щем х.


Формат вывода

Для каждого теста, выход линии два целых числа, представляющий минимальное число инверсии, номер программы (номер программы по модулю 998,244,353).
Если решение не является «-1 -1» .


образец

ввод пробы

3
4
1 2
1 3
4 5
4 6
2
1 1
1 1
3
1 2
3 4
5 6

Пример вывода

2 4
-1 -1
0 1


Диапазон данных и советы

Для получения 20% от данных:

$ П \ leqslant 20 $

$ Т = 1 $

К 100% данных:

$ П \ leqslant {10} ^ 5 $

$ T \ leqslant 50 $

$ 1 \ leqslant х, у \ leqslant 2n $


решение проблемы

Смотрите этот вопрос, вы должны думать о решении с использованием математического метода, то вы холодно.

Таким образом, чтобы рассмотреть, цифровой передней к задней стороне карты даже цифровой стороне, переворачивать каждая карта эквивалентна обратной стороне, и наша цель состоит в том, чтобы сделать из всех точек в каждом Юником блок-схеме не более 1 ,

Но на этот раз, он делится на три случая:

  На фиг. 1. Если есть число ребер в пределах блока больше, чем количество точек Unicom, то, очевидно, не отвечали, напрямую выводит «-1 -1» кнопку.

  2. Если на фигурах есть ссылка блок в пределах числа ребер равен числу точек, то блок представляет собой кольцо Unicom дерева, то мы проводим по часовой стрелке и против часовой стрелки, соответственно, это быстро Unicom, видит необходимость изменить направление , чтобы стать меньшим числом Если ответ в обоих направлениях одинаковы, то номер программы 2, и 1 в противном случае.

  Рисунок 3. Если есть число ребер в блоке равного количества очков -1 Unicom, China Unicom этот блоком является деревом, то вы считаете, используя статистический DP ответ, но, очевидно, мы должны все точки для дерева корневой перспективы опять же, насилие бежать, то время сложность, очевидно, очень высока, однако, мы обнаружили, что при каждом изменении влияет только на корень даже между ним и его материнская сторона ответит, но мудрость +1 на ответ, или - 1, так что мы можем вычислить ответ в диапазоне времени, отведенного.


время кода

#include<bits/stdc++.h>
using namespace std;
struct rec
{
	int nxt;
	int to;
	bool w;//边权为1表示从正面连向反面
}e[200002];
int n;
int head[200001],cnt;
int b,d;
bool vis[200001];
int st,ed,po;
int sta[200001],top;
long long dp[200001],flag[200001];
long long ans,sum,num;
void pre_work()//多测不清空,爆零两行泪TAT……
{
	ans=0;
	sum=cnt=1;
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	memset(dp,0,sizeof(dp));
	memset(flag,0,sizeof(flag));
}
void add(int x,int y,int w)//建边
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=w;
	head[x]=cnt;
}
void pre_dfs(int x)//跑每一个联通块,计算点数和边数
{
	d++;
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	{
		b++;
		if(!vis[e[i].to])
			pre_dfs(e[i].to);
	}
}
void dfs(int x,int fa)//DP前对每一个联通块进行预处理
{
	flag[x]=0;
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt)
	{
		if(e[i].to==fa)continue;
		if(!vis[e[i].to])
		{
			dfs(e[i].to,x);
			flag[x]+=flag[e[i].to]+e[i].w;
		}
		else
		{
			st=x;
			ed=e[i].to;
			po=i;
		}
	}
}
void pro_dfs(int x,int fa)//DP统计答案
{
	sta[++top]=dp[x];
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa&&i!=po&&i!=(po^1))
		{
			dp[e[i].to]=dp[x]+(e[i].w?-1:1);//换根之后的+1或者-1
			pro_dfs(e[i].to,x);
		}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		pre_work();
		for(int i=1;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			add(x,y,1);
			add(y,x,0);
		}
		for(int i=1;i<=2*n;i++)
			if(!vis[i])
			{
				b=d=0;
				pre_dfs(i);
				if(b/2>d)//判断是否有解
				{
					puts("-1 -1");
					goto nxt;//直接跳到结尾,和continue功能类似,但是可以指定跳转位置
				}
			}
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=2*n;i++)
		{
			if(!vis[i])
			{
				st=ed=po=top=0;
				num=1;
				dfs(i,0);
				dp[i]=flag[i];
				pro_dfs(i,0);
				if(!st)//如果是一棵树
				{
					sort(sta+1,sta+top+1);
					for(int j=2;j<=top;j++)
					{
						if(sta[j]!=sta[1])break;
						num++;
					}
					ans+=sta[1];
				}
				else//是一棵基环树
				{
					РО% = 2; 
					ЕСЛИ (ДП [СТ] + РО == ДП [ED] + (РО ^ 1).) , NUM = 2; 
					остальное , NUM = 1;. 
					АНС + = мин (ДП [СТ] + РО, ДП [ЭД] + (^ РО 1.)); 
				} 
				SUM = СУММ NUM% 998 244 353 *; 
			} 
		} 
		Е ( "% ДНУ ДНУ% \ n-", АНС, СУММА); 
		NXT :; // выше "Гото NXT;" прыжок положение 
	} 
	возвращает 0; 
}

Р.П. ++

рекомендация

отwww.cnblogs.com/wzc521/p/11222273.html
рекомендация