HDU - 5765 Bonds 思维 + sosdp(子集和dp)

HDU - 5765

一个bond肯定把n个点分成两个连通块, 并且每个集合对应一个bond, 因为当前这个集合属于第一个连通块,

那么它的补集就输入另一个连通块, ok[ mask ] 表示 mask这些点集能否成为一个连通块。

我们称一个分配方案mask是好的当且仅当ok[ mask ] == true && ok[ ~mask ] = true;

那么我们考虑一条边(u, v)属于多少个bond, 也就是总的合法的分配方案  减去 u, v在同一个点集里的方案数。

我们考虑sosdp求一个父集和就ok了。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 3e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = (int)1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

int n, m, all, G[20];
int U[20 * 20], V[20 * 20];
bool ok[1 << 20];
int c[1 << 20];

void init() {
    all = 0;
    for(int i = 0; i < (1 << n); i++) {
        ok[i] = false;
        c[i] = 0;
    }
    for(int i = 0; i < n; i++) {
        G[i] = 0;
    }
}

int main() {
    int cas = 0;
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        init();
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &U[i], &V[i]);
            G[U[i]] |= 1 << V[i];
            G[V[i]] |= 1 << U[i];
        }
        ok[0] = true;
        for(int i = 0; i < n; i++) {
            ok[1 << i] = true;
        }
        for(int mask = 0; mask < (1 << n); mask++) {
            if(!ok[mask]) continue;
            for(int i = 0; i < n; i++) {
                if(mask >> i & 1) continue;
                if(!(G[i] & mask)) continue;
                ok[mask | (1 << i)] = true;
            }
        }
        for(int mask = 0; mask < (1 << n); mask++) {
            int fmask = (~mask) & ((1 << n) - 1);
            if(!ok[mask] || !ok[fmask]) continue;
            all++;
            c[mask]++;
        }
        for(int i = 0; i < n; i++) {
            for(int mask = 0; mask < (1 << n); mask++) {
                if(mask >> i & 1) {
                    c[mask ^ (1 << i)] += c[mask];
                }
            }
        }
        all >>= 1;
        printf("Case #%d: ", ++cas);
        for(int i = 1; i <= m; i++) {
            int ans = all - c[(1 << U[i]) | (1 << V[i])];
            printf("%d%c", ans, " \n"[i == m]);
        }
    }
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/11505694.html

时间: 2024-10-03 21:57:00

HDU - 5765 Bonds 思维 + sosdp(子集和dp)的相关文章

HDU 5765 Bonds(状压DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5765 [题目大意] 给出一张图,求每条边在所有边割集中出现的次数. [题解] 利用状压DP,计算不同的连通块,对于每条边,求出两边的联通块的划分方案数,就是对于该点的答案. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int n,m,T,Cas=1

HDU 5765 Bonds 巧妙状压暴力

题意:给一个20个点无向连通图,求每条边被多少个极小割集包括 分析:极小割集是边的集合,很显然可以知道,极小割集恰好吧原图分成两部分(这个如果不明白可以用反证法) 然后就是奉上官方题解:http://bestcoder.hdu.edu.cn/blog/ 2016多校训练第4场1003 其实大体思路就是每次枚举一种可能的割集,即状压枚举,其中有不合法的,可以通过预处理标记所有的合法状态 剩下的就是贴代码了,好好看代码细节才是最重要的 #include <cstdio> #include <

HDU 5765 Bonds

比赛时候想了好久,不会.看了官方题解才会...... Bond是极小割边集合,去掉一个Bond之后,只会将原图分成两个连通块. 假设某些点构成的集合为 s(点集中的点进行状压后得到的一个十进制数),那么剩下的点构成的集合为 t=(1<<n)-1-s 如果s是连通的,t也是连通的,那么跨越s.t集合的边的答案就+1(即跨越s.t集合的边构成一个Bond).  因此,只需枚举 s 即可. 接下来问题转变成了以下两个问题: 1.如何判断某个点集合是否连通:状压DP预处理. 2.如何让跨越s.t集合的

hdu 1208 Pascal&#39;s Travels (子状态继承dp)

Pascal's Travels Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1774    Accepted Submission(s): 781 Problem Description An n x n game board is populated with integers, one nonnegative integer

HDU 1561The more, The Better(树形DP)

HDU 1561  The more, The Better 题目大意就不说了 直接DP[i][j]表示i为跟节点的子树上攻克j个城堡的所能获得的最多宝物的数量 DP[fa][j] = MAX{DP[fa][i-k] + DP[child][k]}; 首先一个问题就是说如果子树u下的任意子节点被选择了,那么u是一定需要选择的,怎么在DP时保证准确性,其实这个很好解决,我们在计算时是需要枚举k(子节点的攻克数量)的,那么我们迫使k<j就可以了,这样的话DP[fa][j] 就不会被子节点的DP[ch

hdu 1561The more, The Better(树形dp&amp;01背包)

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4949    Accepted Submission(s): 2918 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝

HDU 4114 Disney&#39;s FastPass (状压DP)

题意:给定 n 个区域,然后给定两个区域经过的时间,然后你有 k 个景点,然后给定个每个景点的区域和有票没票的等待时间,从哪些区域能够得到票,问你从景点1开始,最后到景点1,而且要经过看完这k个景点. 析:一个状压DP,dp[s1][s2][i] 表示已经访问了 s1 中的景点,拥有 s2 的票,当前在 i 区域,然后两种转移一种是去下一个景点,另一种是去下一个区域拿票.当时输入,写错了,卡了好长时间.... 代码如下: #pragma comment(linker, "/STACK:10240

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12341   Accepted: 7204 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was