UVA - 818 Cutting Chains 深度好文 仔细研读

What a find! Anna Locke has just bought several links of chain some of which may be connected. They
are made from zorkium, a material that was frequently used to manufacture jewelry in the last century,
but is not used for that purpose anymore. It has its very own shine, incomparable to gold or silver,
and impossible to describe to anyone who has not seen it first hand.
Anna wants the pieces joined into a single end-to-end strand of chain. She takes the links to a
jeweler who tells her that the cost of joining them depends on the number of chain links that must
be opened and closed. In order to minimize the cost, she carefully calculates the minimum number of
links that have to be opened to rejoin all the links into a single sequence. This turns out to be more
difficult than she at first thought. You must solve this problem for her.
Input
The input consists of descriptions of sets of chain links, one set per line. Each set is a list of integers
delimited by one or more spaces. Every description starts with an integer n, which is the number of
chain links in the set, where 1 ≤ n ≤ 15. We will label the links 1, 2, . . . , n. The integers following
n describe which links are connected to each other. Every connection is specified by a pair of integers
i,j where 1 ≤ i, j ≤ n and i ̸= j, indicating that chain links i and j are connected, i.e., one passes
through the other. The description for each set is terminated by the pair ‘-1 -1’, which should not be
processed.
The input is terminated by a description starting with n = 0. This description should not be
processed and will not contain data for connected links.
Output
For each set of chain links in the input, output a single line which reads
Set N: Minimum links to open is M
where N is the set number and M is the minimal number of links that have to be opened and closed
such that all links can be joined into one single chain.
Sample Input
5 1 2 2 3 4 5 -1 -1
7 1 2 2 3 3 1 4 5 5 6 6 7 7 4 -1 -1
4 1 2 1 3 1 4 -1 -1
3 1 2 2 3 3 1 -1 -1
3 1 2 2 1 -1 -1
0
Sample Output
Set 1: Minimum links to open is 1
Set 2: Minimum links to open is 2
Set 3: Minimum links to open is 1
Set 4: Minimum links to open is 1
Set 5: Minimum links to open is 1

题意:有n个圆环,其中有一些已经扣在了一起。现在需要打开尽量少的圆环,使得所有圆环可以组成一条链,例如,有5个圆环,1-2,2-3,4-5,则需要打开一个圆环,如圆环4,然 后用它穿过圆环3和圆环5后再次闭合4,就可以形成一条链:1-2-3-4-5。

思路:从n个圆环中任意选择圆环,这就是枚举子集。所以这道题目可以用二进制枚举来做。

    那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断:

    ①:每个圆环的分支数都必须小于等于2,大于2个肯定就不能成为单链了。

    ②:不能存在环。

    ③:连通分支数-1不能大于打开圆环数。

    判断是否存在圆环和连通分支数都可以用dfs来实现。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,cnt,number;
int map[20][20],vis[20],ans;

bool two(int s) {
    for(int i=0; i<n; i++) {
        int cnt = 0;
        for(int j=0; j<n; j++) {
            if(map[i][j] && !(s & (1 << j )) && !(s & (1 << i))) {
                cnt++;
                if(cnt == 3) return true;
            }
        }
    }
    return false;
}

bool dfs(int x,int f,int s) {
    vis[x] = 1;
    for(int i=0; i<n; i++) {
        if(map[x][i]){
            if(i == f || (s & (1 << i))) continue;
            if(vis[i]) return true;
            if(dfs(i,x,s)) return true;
        }
    }
    return false;
}

bool circle(int s) {
    memset(vis,0,sizeof(vis));
    for(int i=0; i<n; i++) {
        if(!vis[i] && !(s & (1 << i))) {
            number++;
            if(dfs(i,-1,s)) return true;
        }
    }
    return false;
}

int calc(int s) {
    int cnt = 0;
    for(int j=0; j<n; j++) {
        if(s & (1 << j)) cnt++;
    }
    return cnt;
}

void solve() {
    ans = 100000;
    for(int i=0; i<(1<<n); i++) {
        number = 0;
        if(two(i) || circle(i)) continue;
        int count = calc(i);
        if(number - 1  <= count ) ans = min(ans,count);
    }
}

int main() {
    int a,b,kase = 0;
    while(cin >> n && n) {
        memset(map,0, sizeof(map));
        while(cin >> a >> b &&  a != -1 && b != - 1) {
            map[a - 1][b - 1] = 1;
            map[b - 1][a - 1] = 1;
        }
        solve();
        cout << "Set " << ++kase << ": Minimum links to open is " << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值