UVA-818

UVA-818 Cutting Chains

这个题想了很久,还是没有思路,就去看了别的大佬的博客
结果大佬们好像都喜欢用二进制,我作为一个一看到二进制就头疼的渣渣
最后还是看了这位大佬的

没有二进制!!

https://blog.csdn.net/playwfun/article/details/44346619
先上一下易出错的测试数据
Sample Input
2 1 2 1 2 -1 -1
2 1 2 2 1 1 2 2 1 -1 -1
3 1 2 -1 -1
0

这里没有用二进制,而是用双递归来代替

    dfs(p+1,d);
    int temp[2][20];
    for(int i=1; i<=n; i++)
    {
        temp[0][i]=te[p][i];
        temp[1][i]=te[i][p];
        te[p][i]=te[i][p]=0;
    }
    dfs(p+1,d+1);
    for(int i=1; i<=n; i++)
    {
        te[p][i]=temp[0][i];
        te[i][p]=temp[1][i];
    }
    //对于每个环都可以选择是否open

temp数组用来储存te的数据,dfs之后要将数据再改回去
dfs中的参数 p是当前考虑的环的编号,d是当前打开了d个环

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
int te[20][20];
int n,ans;
int vis[30];
bool judge()//如果分支大于2,return false
{
    int c[30]= {0};
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(te[i][j])
            {
                if(++c[i]>=5)
                    return false;
                if(++c[j]>=5)
                    return false;
            }
        }
    }
    return true;
}
bool huan(int u,int fa)//如果是环return true
{
    vis[u]=1;
    for(int v=1; v<=n; v++)
    {
        if(v!=u&&v!=fa)
        {
            if(te[u][v]||te[v][u])
            {
                if(vis[v])
                    return true;
                else
                    huan(v,u);
            }
        }
    }
    return false;
}
void dfs(int p,int d)
{
    if(d>ans)
        return;
    if(p==n+1)
    {
        if(judge())
        {
            int ok=1;
            memset(vis,0,sizeof(vis));
            int cnt=0;
            for(int i=1; i<=n; i++)
            {
                if(!vis[i])
                {
                    cnt++;
                    if(huan(i,-1))
                        ok=0;
                }
            }
            //cnt是链数
            //比如1 2 2 3 4 5
            //本来是有两条链,但是如果将4 open(te[4][5]=0,te[5][4]=0),4与5就不再相连
            //链数就变成了3,此时d是1
            //下面的cnt=cnt-d,结果中的cnt就是原来的链数
            if(ok)
            {
                cnt=cnt-d;
                if(cnt<=d+1)//本来的链数必须不大于d+1,不然无法将所有的环连成一条链
                    ans=d;
            }
        }
        return;
    }
    dfs(p+1,d);
    int temp[2][20];
    for(int i=1; i<=n; i++)
    {
        temp[0][i]=te[p][i];
        temp[1][i]=te[i][p];
        te[p][i]=te[i][p]=0;
    }
    dfs(p+1,d+1);//如果将p环open,就要将p环连接的所有环都断开
    for(int i=1; i<=n; i++)
    {
        te[p][i]=temp[0][i];
        te[i][p]=temp[1][i];
    }
}
int main()
{
    int ccase=0;
    while(cin>>n&&n)
    {
        ans=n;
        ccase++;
        int x,y;
        memset(te,0,sizeof(te));
        while(cin>>x>>y)
        {
            if(x==-1)
                break;
            te[x][y]=te[y][x]=1;
        }
        dfs(1,0);
        printf("Set %d: Minimum links to open is %d\n",ccase,ans);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值