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;
}    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值