L2-010. 排座位

L2-010. 排座位

关键字:用multimap实现并查集

布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

输入格式:

输入第一行给出3个正整数:N(<= 100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:“宾客1 宾客2 关系”,其中“关系”为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

输出格式:

对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出“No problem”;如果他们之间并不是朋友,但也不敌对,则输出“OK”;如果他们之间有敌对,然而也有共同的朋友,则输出“OK but…”;如果他们之间只有敌对关系,则输出“No way”。

输入样例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

输出样例:

No problem
OK
OK but…
No way

C语言 标准的并查集算法

AC解答(不是我自己写的)

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
int w[105][105],f[105];
int fine(int v)
{
	if(f[v]==v) return v;
	return f[v]=fine(f[v]);
}
void mage(int v,int w)
{
	int t1=fine(v);
	int t2=fine(w);
	if(t1!=t2)
		f[t1]=t2;
}
int main()
{
	int n,m,k,i,a,b,c;
	scanf("%d%d%d",&n,&m,&k);
	for(i=0; i<n; i++)
	{
		f[i]=i;
	}
	for(i=0; i<m; i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		if(c==1)
			mage(a,b);
		w[a][b]=c;
		w[b][a]=c;
	}
	for(i=0; i<k; i++)
	{
		scanf("%d%d",&a,&b);
		if(fine(a)==fine(b)&&w[a][b]!=-1) printf("No problem\n");
		else if(fine(a)!=fine(b)&&w[a][b]!=-1) printf("OK\n");
		else if(fine(a)==fine(b)&&w[a][b]==-1)  printf("OK but...\n");
		else printf("No way\n");
	}
}

22/25代码

先看代码

/*
	Name: L2-010. 排座位
	Author: spencercjh
	Date: 2017年10月22日 12:11:23
	Description:团体程序设计天梯赛-练习集 GPLT
				https://www.patest.cn/contests/gplt/L2-010
	ref:http://blog.csdn.net/lhrsdl/article/details/38119577
		http://www.cplusplus.com/reference/map/multimap/find/
		http://www.cnblogs.com/dongsheng/archive/2013/09/10/3311594.html
		http://www.cplusplus.com/reference/map/multimap/equal_range/
*/
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<numeric>
#include<stack>
using namespace::std;
int main()
{
	int N,M,K;
	scanf("%d %d %d",&N,&M,&K);
	multimap<int,int> Friend;
	multimap<int,int> Enemy;
	for(int i=1; i<=N; i++)	//初始化mutimap 
	{
		Friend.insert(pair<int,int>(i,i));
		Enemy.insert(pair<int,int>(i,i));
	}
	auto j=Friend.begin(),k=Friend.begin(),p=Enemy.begin(),q=Enemy.begin();
	for(int i=0; i<M; i++)
	{
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		if(c==1)	
		{
			j=Friend.find(a);
			k=Friend.find(b);
			if(j->first!=k->first)
			{
				Friend.insert(pair<int,int>(a,b));
				Friend.insert(pair<int,int>(b,a));
			}
		}
		else if(c==-1)
		{
			p=Enemy.find(a);
			q=Enemy.find(b);
			if(p->first!=q->first)
			{
				Enemy.insert(pair<int,int>(a,b));
				Enemy.insert(pair<int,int>(b,a));
			}
		}
	}
	for(int i=0; i<K; i++)
	{
		int a,b;
		scanf("%d %d",&a,&b);
		bool friendflag=false,enemyflag=false,commonfriend=false;
		auto Friendbeg=Friend.lower_bound(a),Friendend=Friend.upper_bound(a);
		while(Friendbeg!=Friendend)
		{
			if(Friendbeg->second==b)
			{
				friendflag=true;
				break;
			}
			Friendbeg++;
		}
		auto Enemybeg=Enemy.lower_bound(a),Enemyend=Enemy.upper_bound(a);
		while(Enemybeg!=Enemyend)
		{
			if(Enemybeg->second==b)
			{
				enemyflag=true;
				break;
			}
			Enemybeg++;
		}
		auto commonbeg=Friend.lower_bound(b),commonend=Friend.upper_bound(b);
		if(enemyflag)	//双方有敌对关系,寻找双方的共同朋友
		{
			Friendbeg=Friend.lower_bound(a);	//之前Friendbeg已经经历过一个循环,在此规整
			while(Friendbeg!=Friendend)
			{
				commonbeg=Friend.lower_bound(b);	//之前commonbeg已经经历过一个循环,在此规整
				while(commonbeg!=commonend)
				{
					if(Friendbeg->second==commonbeg->second)
					{
						commonfriend=true;
						break;
					}
					commonbeg++;
				}
				Friendbeg++;
			}
		}
		if(friendflag)
			printf("No problem\n");
		else if(enemyflag)
		{
			if(commonfriend)
				printf("OK but...\n");
			else
				printf("No way\n");
		}
		else
			printf("OK\n");
	}
}

mutimap在本题中的使用

mutimap:http://www.cplusplus.com/reference/map/multimap/
关系比较复杂,需要2个mutimap——Friend,Enemy。

数据存储——

mutimap(key,value).将2人关系存入mutimap中,标识符1加入Friend,标识符为-1加入Enemy。你会发现我插入的时候很重复,(a,b)和(b,a)都要插进去,首先是因为如果只插入(a,b),查询(b,a)的关系的时候就会出问题,其次后面寻找敌人的共同朋友,也需要b作为key去查他的朋友。(但是讲道理,并查集作为树和森林的应用,这样操作打乱了结点之间应该有的正确逻辑关系。

.............
				Friend.insert(pair<int,int>(a,b));
				Friend.insert(pair<int,int>(b,a));
..............

开始查询——

这里就涉及到mutimap的遍历:http://www.cnblogs.com/dongsheng/archive/2013/09/10/3311594.html
这里我使用的是链接中介绍的第二种,用lower_bound和upper_bound找到输入key(a)的value的上下界,遍历key的所有value,在其中查找第二个人(b)。

auto Friendbeg=Friend.lower_bound(a),Friendend=Friend.upper_bound(a);
while(Friendbeg!=Friendend)
{
	if(Friendbeg->second==b)
	{
		friendflag=true;
		break;
	}
		Friendbeg++;
}

Enemy同理。

题目又多了一个要求,即还要考察敌人之间的共同朋友,这也是我最为担心的部分。这里会有一个嵌套循环,我一直怀疑为超时,幸好没有:)。外层循环将a作为key遍历value,内层循环将b作为key遍历value,这期间找到一个相同的值就说明这2个敌人有共同敌人。

		auto commonbeg=Friend.lower_bound(b),commonend=Friend.upper_bound(b);
		if(enemyflag)	//双方有敌对关系,寻找双方的共同朋友
		{
			Friendbeg=Friend.lower_bound(a);	//之前Friendbeg已经经历过一个循环,在此规整
			while(Friendbeg!=Friendend)
			{
				commonbeg=Friend.lower_bound(b);	//之前commonbeg已经经历过一个循环,在此规整
				while(commonbeg!=commonend)
				{
					if(Friendbeg->second==commonbeg->second)
					{
						commonfriend=true;
						break;
					}
					commonbeg++;
				}
				Friendbeg++;
			}
		}

最后按照题目要求的逻辑输出对应语句

		if(friendflag)
			printf("No problem\n");
		else if(enemyflag)
		{
			if(commonfriend)
				printf("OK but...\n");
			else
				printf("No way\n");
		}
		else
			printf("OK\n");
	}

总结

使用stl_mutimap编程,虽然代码行数比C语言标准并查集算法多了一倍,但泛型编程风格代码容易读容易写容易懂,我更喜欢这样的编码方式。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值