bfs寻找增广路

本文介绍了Dumbulidone和Euphemia玩的一个卡片游戏,目标是在Euphemia赢得游戏的前提下,找出最多能选择的信封数量。问题转化为寻找没有环的增广路径。通过将卡片视为节点,信封视为边,利用BFS算法判断是否存在增广路径,并反转路径上的选择以增加获胜策略。文章讨论了如何构建图,判断环的存在,以及如何进行增广路径的搜索,帮助理解这种类型的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

选信封

【问题描述】

DumbulidoneEuphemia玩一个挑卡片游戏.

Dumbulidone会给出N对信封,每个信封里有两张不同颜色的卡片,她会让Euphemia从中挑选任意个信封,但是一对信封中最多只能挑选一个,(信封是透明的,可以看到里面卡片颜色)。等Euphemia挑好后,Dumbulidone会尝试从Euphemia挑出的信封中再选出若干个(不可以不取),把其中的卡片取出,若存在一种方案使得取出的卡片中,每种颜色的卡片都有偶数张,那么Dumbulidone就赢了。Euphemia想知道在自己赢的前提下,她最多能选出多少信封。

 

【输入格式】

第一行一个整数N

接下来N行,每行4个整数,描述一对信封中卡片颜色,前两个是一个信封中的,后两个是一个信封中的。

 

【输出格式】

    一个整数,表示答案。

 

【输入输出样例一】

game.in

game.out

4

0 1 0 5

5 1 0 5

1 2 0 1

1 5 2 0

3

 

【输入输出样例二】

game.in

game.out

6

1 4 1 4

2 4 2 4

0 3 0 3

0 4 0 4

4 3 4 3

1 3 1 3

4

 

【数据范围】

 对于30%的数据满足N<=10

对于100%的数据满足N<=300,所有数<=10^7.   

 

最近的训练感觉越来越难。。。苟蒻就是没办法。。。记录下新知识以后说不定用得上吧。。

一开始看到这题想到爆搜,感觉骗个三十分有??但是时间关系没去实践

后来看了题解说是要增广路。。。。唉最不会这个了!!!

花了差不多三天断断续续才大概理解了吧(出题方给我的例程居然是WA0分的。。。)

首先把每张卡片看做一个点,那么每个信封就是一条边,任务是挑最多的边使得没有环生成

对于每对边先各尝试一边能否直接加入,能的话当然最好,如果不能就要尝试对之前的选择进行调整

调整就是找增广路。。大概是找一条未选边->已选边->未选边...->未选边这样的路,然后将沿途所有点取反

称为一次增广

那么如何确定边?

显然,每对给出的边(点)间连一条边,接下来对所有未选边进行一次dfs判断加入后有无环,

有环的话就把环上的每一条边(点)和它连一条边,显然增广的终点是某条加入后不会形成环的边

大概就是这样把。。。

 

 

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<cstdlib>
#include<map>
#include<cmath>
using namespace std;

const int maxn = 600;

struct E{
	int u,v,use;
	E () {use = 0;}
}edgs[2*maxn];

struct EP{
	int v,p;
};

int n,i,j,fa[4*maxn],num[4*maxn],cur = 0,From[2*maxn],visp[4*maxn];
bool ok[2*maxn],vis[2*maxn],r[2*maxn];

vector <EP> vp[4*maxn];
vector <int> ve[2*maxn];
queue <int> q;

int father (int k)
{
	return k == fa[k]?k:fa[k] = father(fa[k]);
}

bool Insert (int x)
{
	int fu = father(edgs[x].u);
	int fv = father(edgs[x].v);
	if (fu == fv) return false;
	fa[fu] = fv;
	edgs[x].use = 1;
	return true;
}

bool dfs (int now,int to,int sy)
{
	if (now == to) return true;
	visp[now] = sy;
	for (int l = 0; l < vp[now].size(); l++)
	{
		int To = vp[now][l].v;
		if (visp[To] == sy) continue;
		int Num = vp[now][l].p;
		r[Num] = true;
		if (dfs(To,to,sy)) return true;
		r[Num] = false;
	}
	return false;
}

void Build (int x)
{
	int l;
	memset(ok,false,sizeof(ok));
	memset(r,-1,sizeof(r));
	memset(visp,-1,sizeof(visp));
	for (l = 0; l <= x; l++) ve[l].push_back(l^1);
	for (l = 0; l <= x; l++)
	if (!edgs[l].use)
	{
		ok[l] = true;
		memset(r,false,sizeof(r));
		if (!dfs(edgs[l].u,edgs[l].v,l)) continue;
		ok[l] = false;
		for (j = 0; j < x; j++) if (r[j]) ve[l].push_back(j);
	}
}

bool bfs (int x)
{
	memset(vis,false,sizeof(vis));
	memset(From,-1,sizeof(From));
	int end = -1;
	q.push(x);
	vis[x] = true;
	while (!q.empty())
	{
		int k = q.front();
		q.pop();
		for (int l = 0; l < ve[k].size(); l++)
		{
			int To = ve[k][l];
			if (vis[To]) continue;
			vis[To] = true;
			if ((edgs[To].use ^ edgs[k].use))
			{
				From[To] = k;
				if (ok[To])
				{
					end = To;
					while (!q.empty()) q.pop();
					break;
				}
				q.push(To);
			}
		}
	}
	if (end == -1) return false;
	for (; end != -1; end = From[end]) edgs[end].use ^= 1;
	return true;
}

void Clear()
{
	for (j = 0; j <= cur; j++) fa[j] = j;
	for (j = 0; j < 4*n; j++) vp[j].clear(); 
	for (j = 0; j < 2*n; j++) ve[j].clear();
	for (j = 0; j < 2*i; j++)
		if (edgs[j].use)
		{
			fa[father(edgs[j].u)] = father(edgs[j].v);
			vp[edgs[j].u].push_back((EP){edgs[j].v,j});
			vp[edgs[j].v].push_back((EP){edgs[j].u,j});
		}
}

int main()
{
	#ifndef ONLINE_JUDGE
	#ifndef YZY
	  freopen("game.in","r",stdin);
	  freopen("game.out","w",stdout);
	#else
	  freopen("yzy.txt","r",stdin);
	#endif
	#endif
	cin >> n;
	j = -1;
	for (i = 0; i < 2*n; i++)
	{
		scanf("%d%d",&edgs[i].u,&edgs[i].v);
		num[++j] = edgs[i].u;
		num[++j] = edgs[i].v;
	} 
	sort (num,num + j + 1);
	for (i = 1; i <= j; i++)
	  if (num[i] != num[i-1])
	    num[++cur] = num[i];
	for (i = 0; i < 2*n; i++)
	{
		edgs[i].u = lower_bound(num,num + cur + 1,edgs[i].u) - num;
		edgs[i].v = lower_bound(num,num + cur + 1,edgs[i].v) - num;
	}
	for (i = 0; i < n; i++)
	{
		Clear();
		if (Insert(2*i)) continue;
		if (Insert(2*i+1)) continue;
		Build(2*i+1);
		if (bfs(2*i)) continue;
		bfs(2*i+1);
	}
	int ans = 0;
	for (i = 0; i < 2*n; i++)
	  if (edgs[i].use) 
	  	++ans;
	cout << ans;
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值