hdu 3118 Arbiter 二分图的性质

题目意思我就借别人博客里的啦微笑,素质借用,附上原文地址http://blog.sina.com.cn/s/blog_68d7b63901013guv.html

Arbiter

     “仲裁者”是《星际争霸》科幻系列中的一种太空船。仲裁者级太空船是神族的战船,专门提供精神力支援。不像其他战船的人员主要是战士阶级,仲裁者所承载的都是统治阶级。统治者以仲裁者为基地,用时空操控来提供支援。
       仲裁者可以克服时空限制,撕裂时空,产生裂缝,制造涡洞,把另一个空间连接到仲裁者所在空间,可以用来运送人员,跨越长途星际。
       正当仲裁者广泛用于运输的时候,一艘仲裁者的船长 KMXS 发出警告,有些人员在他的船上完成旅程之后,得到严重的精神错乱。他用小白鼠做动物实验,找到了原因,是生物化学中的“手性”!
       每个人都有手性,是左手性或者右手性。事实上,所有人的生存都必须依靠相同手性的食物。一个人乘坐仲裁者从一个星球到另一个星球的时候,他的手性会改变,(从左手性变成右手性,或者从右手性变成左手性。)如果一个人经过长途旅行,最后回到自己的星球,可是他的手性却可能改变成跟原来的相反,那就会造成致命的精神错乱,甚至死亡。 
       KMXS 拥有星球之间的航道图。他需要禁止通过航道的最少数目,以致无论一个人从哪里出发,当他回到自己的星球,会是安全的。KMXS请求你的帮助。

Input

  第一行输入有一个整数 T,表示测试用例的数目。
  每个用例的第一行有两个整数 N 和 M,表示星球的数目和航道的数目。随后的 M 行表示航道,每个 (u, v) 代表在星球 u 和星球 v 之间有一条双向的航道(u 不等于 v)。

Output

        每个测试用例的结果输出一行,用一个整数表示KMXS为了要避免人们精神错乱, 必须禁止的最少航道数目。

Constraints

    0 < T <= 10
    0 <= N <= 15 0 <= M <= 300
    0 <= u, v < N在两个星球之间可以有超过一条航道

就是问你至少要去掉几条边,才能使一个人从任何一个星球出发,然后转个圈回到自己的星球经过的边的数目是偶数。

二分图就有这个性质,二分图中若存在环,环的边数一定是偶数。数据不是很大,可以枚举。一共n个顶点,用2 ^(n-1)次方来表示状态。

例如n = 5,00001(二进制)表示顶点0属于集合1,顶点1,2,3,4,属于集合2.如果同一个集合里的两个顶点有边相连,这条边就是要去掉的(二分图的性质)。

所以我们枚举每种状态,然后找出最少的不合法的边的数码,即同一个集合里的顶点相连的边。这就是我们要的答案了。

一开始我是找出连接两个集合的边,即边的一个顶点在集合1,另一个顶点在集合2的边,然后用边的总数m减去这样的边,这样就可以少一半的操作,结果果断wa!

非要我改成第一种找法,不知道是数据问题还是方法问题,求过路的看官给个解答。

AC代码:

#include<stdio.h>

int main()
{
	int T,n,m;
	scanf("%d",&T);
	while(T--)
	{
		int map[20][20] = {0},a,b;
		scanf("%d%d",&n,&m);
		for(int i = 0;i < m;++i)
		{
			scanf("%d%d",&a,&b);
			map[a][b]++;
			map[b][a]++;
		}
		int min = 0x7fffffff;
		for(i = 1;i < (1 << n) - 1;++i)//枚举每个状态
		{
			int sum = 0;
			for(int j = 0;j < n;++j)//对每个状态的每一位进行操作
			{
				if((1 << j) & i)//如果i的这一位为1,表示属于集合2
				{
					for(int k = j + 1;k < n;++k)   //那么就找出同样是集合2的点,然后sum加上他们之间不合法的边
						if((1 << k) & i)
							sum += map[j][k];
				}
				else
				{
					for(int k = j + 1;k < n;++k)//同理,找出同是集合1的点。
						if(!((1 << k) & i))
							sum += map[j][k];
				}
			}
			if(sum < min) min = sum;这就是最少要去掉的边
		}
		printf("%d\n",min == 0x7fffffff?0:min);
	}
	return 0;
}	
wa代码
#include<stdio.h>

int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        int map[20][20] = {0},a,b;
        scanf("%d%d",&n,&m);
        for(int i = 0;i < m;++i)
        {
            scanf("%d%d",&a,&b);
            map[a][b]++;
            map[b][a]++;
        }
        int min = 0x7fffffff;
        for(i = 1;i < (1 << n) - 1;++i)
        {
            int sum = 0;
            for(int j = 0;j < n;++j)
            {
                if((1 << j) & i)
                {
                    for(int k = j + 1;k < n;++k)
                    {
                        if(!((1 << k) & i))
                            sum += map[j][k];
                    }
                }
            }
            if(m - sum < min)
                min = m - sum;
        }
        printf("%d\n",min == 0x7fffffff?0:min);
    }
    return 0;
}    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值