UVA 818 Cutting Chains (暴力二级制枚举+dfs)

35 篇文章 0 订阅
5 篇文章 0 订阅

题目网址点击打开链接

这个题有毒,题意

大概意思应该是:选几个珠子去open。然后该珠子和其他就断开了。然后拿剩下的链去以这些open的珠子为点,去连接,看能不能连成一串。。求最少的open个数。

思路:n为15.利用位运算去枚举哪几个珠子要open。然后判断剩下珠子有没有超过2个分支或者形成环,如果没有,在判断剩下的链个数有没有超过open个数-1.如果条件都符合,那么保留下最小最为答案。

。。。

后来写注释的时候突然发现一个问题对于 f==i这个条件?

出一组样例例如

2
1 2 2 1 -1 -1

按我的对题目的理解答案应该是1;而程序是0

4

1 2 2 1 3 4 4 3

我觉得答案是2 而程序是1

翻了一下大家好像都是这样写的,疑惑中。。。(说不准,某个傻逼又把题意理解错了)


后记:

傻逼,人家不是珠子,人家是环,圆环, 1 2  2 1 就是两个圈圈已经套在了一起,就是个链没差;

1 2 2 1 3 4 4 3 只需解开一个换3 然后把3 和2 4 连上 就是个链(想象一下荧光棒那种圈)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <list>
#include <algorithm>
#include<queue>
#include<vector>

using namespace std;
const int maxn=20;
const int inf=0x3f3f3f3f;
int vis[maxn];
int eg[maxn][maxn];
int n;
int line;
int two(int s) //求每个点的度数 ,不能大于二
{
    int num=0;
    for(int i=0;i<n;i++)
    {
        if(s&(1<<i))
            continue;
        num=0;
        for(int j=0;j<n;j++)
        {
            if(s&(1<<j))
               continue;
            if(eg[i][j])
                num++;
        }
        if(num>2)
            return 1;
    }
    return 0;
}
int dfs(int s,int now,int f)
{
    vis[now]=1;
    for(int i=0;i<n;i++)
    {
        //突然觉得此处f==i有问题
        //f意义之前连过的不能算,比如刚从1-2过来的now=2时,无向图,不能再判一遍2-1(重复)
        //断开的珠子不考虑
        if(s&(1<<i)||!eg[now][i]||f==i)
            continue;
        if(vis[i])//如果再次拜访说明
            return 1;
        if(dfs(s,i,now))
            return 1;
    }
    return 0;
}
//判断有没有圆出现
int cirle(int s)
{
    for(int i=0;i<n;i++)
    {
        if(s&(1<<i)||vis[i])//注意vis过的说明已经在一串链中
            continue;
        line++;//新链产生
        if(dfs(s,i,-1)) //判圆
            return 1;
    }
    return 0;
}
int solve()
{
    int ans=inf;
    int s=(1<<n);//二级制枚举解开的珠子,1为解开
    line=0;
    for(int i=0;i<s;i++)
    {

        line=0;
        memset(vis,0,sizeof(vis));
        if(two(i)||cirle(i))
            continue;
        else
        {
            int res=0;
            int k=i;
            while(k>0)//open个数
            {
                res+=k%2;
                k/=2;
            }
            if(res>=line-1)
            ans=min(ans,res);
        }
    }
    return ans;
}
int main()
{
    int k=0;
    while(cin>>n&&n)
    {
        int a,b;
        k++;
        memset(eg,0,sizeof(eg));
        memset(vis,0,sizeof(vis));
        while(cin>>a>>b&&a!=-1&&b!=-1)
        {
            eg[a-1][b-1]=1;
            eg[b-1][a-1]=1;
        }
        int ans=solve();
        if(ans==inf)
            ans=0;
        printf("Set %d: Minimum links to open is %d\n",k,ans);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值