UVA 818 Cutting Chains(状压 + 暴搜)题解

题意:有1~n个小环,他们中的有些互相扣在一起,问你至少切开几个能把这写小环串成一条链

思路:还是太菜了,题目给的n<=15,显然可以暴力解决。

用二进制表示每个环切还是不切,然后搜索所有情况。当一种情况满足一下两点:1.切完之后每一串连在一起的环应该是一条链,没有分支没有环;2.当一个环被切开,那么他就可以当做任意串的连接点,那么显然切开的点+1>=串的数量。

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 15 + 10;
const int seed = 131;
const ll MOD = 100000007;
const int INF = 0x3f3f3f3f;
int vis[maxn], del[maxn], mp[maxn][maxn];
int n, ans, u, v, ca = 1, flag;
bool branch(){
    int deg = 0;
    for(int i = 1; i <= n; i++){
        deg = 0;
        if(!del[i]){
            for(int j = 1; j <= n; j++){
                if(mp[i][j] && !del[j])
                    deg++;
            }
        }
        if(deg > 2) return false;
    }
    return true;
}
bool dfs(int x, int pre){
    bool yes = true;
    vis[x] = 1;
    for(int i = 1; i <= n; i++){
        if(mp[x][i] && i != pre && !del[i]){
            if(vis[i]) return false;
            yes = dfs(i, x);
            if(!yes) return false;
        }
    }
    return true;
}
bool loop(int &rest){
    memset(vis, 0, sizeof(vis));
    flag = 0;
    for(int i = 1; i <= n; i++){
        if(!vis[i] && !del[i]){
            if(!dfs(i, -1)) return false;
            rest++;
        }
    }
    return true;
}
int main(){
    while(scanf("%d", &n) && n){
        memset(mp, 0, sizeof(mp));
        while(scanf("%d%d", &u, &v) && u != -1 && v != -1){
            mp[u][v] = mp[v][u] = 1;
        }
        int ans = INF, delet, rest;
        for(int i = 0; i < (1 << n); i++){
            memset(del, 0, sizeof(del));
            delet = rest = 0;
            for(int j = 0; j < n; j++){
                if(i & (1 << j)){
                    del[j + 1] = 1;
                    delet++;
                }
            }
            if(!branch() || !loop(rest)) continue;
            //printf("%d
", delet);
            if(delet + 1 >= rest){
                ans = min(ans, delet);
            }
        }
        printf("Set %d: Minimum links to open is %d
", ca++, ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/10083643.html