斯坦纳树应用

点权关键联通

定义\(f[i][bit]\)为联通快里包含\(i\)且关键点状态为\(bit\)的最小花费

初始化\(~_{i=1}^k f[i][1<<i-1]=0;\)

实现:枚举\(bit\),枚举\(i\),枚举\(S\)
\(~~~~~~~~~~\)\(f[i][bit]=min_{S\in bit}\{f[i][S]+f[i][bit-S]-val[i]\}\)(容斥)

\(~~~~~~~~~~\)显然这样仅是合并(填表),还得有向外扩展的部分(刷表)

\(~~~~~~~~~~\)每次枚举\(bit\)最后遍历一遍图:\(f[j][bit]=f[i][bit]+val[j]\)\(e(i,j)\in \{E\}\)
\(~~~~~~~~~~\)注意此时即使\(j\)是关键点也不需要变化\(bit\)

边权有色关键联通

要求同色的关键点必须联通
对于颜色状压处理,状压处理的那些颜色单独作为关键点联通处理

对于之前的颜色状压做子集动规

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <queue>  

using namespace std;  
const int Maxn = 0x3f3f3f3f;  
const int N = 1005, M = 6005, L = 1 << 10;  
int lst[N], f[N][L], nxt[M], to[M], cst[M], g[L], c[12];   
int n, m, k, T, Cn; bool vis[N];  
queue<int> Q;  

template <class T> inline T Min(const T a, const T b) {return a < b? a : b;}  
template <class T> inline void CkMin(T &a, const T b) {if (a > b) a = b;}  

struct point  
{  
    int col, id;  
    #define col(x) a[x].col  
    #define id(x) a[x].id  
}a[12];  

inline bool cmp(const point x, const point y) {return x.col < y.col;}  

inline int get()  
{  
    char ch; bool f = false; int res = 0;  
    while (((ch = getchar()) < '0' || ch > '9') && ch != '-');  
    if (ch == '-') f = true;  
     else res = ch - '0';  
    while ((ch = getchar()) >='0' && ch <= '9')  
        res = (res << 3) + (res << 1) + ch - '0';  
    return f? ~res + 1 : res;  
}  

inline void put(int x)  
{  
    if (x < 0)  
      x = ~x + 1, putchar('-');  
    if (x > 9) put(x / 10);  
    putchar(x % 10 + 48);  
}  

inline void add(const int x, const int y, const int z)  
{  
    nxt[++T] = lst[x]; lst[x] = T; to[T] = y; cst[T] = z;  
    nxt[++T] = lst[y]; lst[y] = T; to[T] = x; cst[T] = z;  
}  

inline void SPFA(const int I)  {  
    int x, y;  
    while (!Q.empty())  {  
        x = Q.front(); 
		vis[x] = false; 
		Q.pop();  
        for (int i = lst[x]; i; i = nxt[i])  
            if (f[y = to[i]][I] > f[x][I] + cst[i])  {  
                f[y][I] = f[x][I] + cst[i];  
                if (!vis[y]) 
			        vis[y] = true, Q.push(y);  
            }   
    }  
}  

inline int solve(const int cnt) {  
    int Cm = 1 << cnt;  
    for (int i = 1; i < Cm; ++i)  {  
        for (int j = 1; j <= n; ++j)  {  
            for (int k = (i - 1) & i; k; k = (k - 1) & i)  
                CkMin(f[j][i], f[j][k] + f[j][i - k]);  //边权不需要容斥 
            if (f[j][i] != Maxn) 
			    vis[j] = true, 
				Q.push(j);  
        }  
        SPFA(i);  
    }  
    int res = Maxn;  
    for (int i = 1; i <= n; ++i) CkMin(res, f[i][Cm - 1]);  
    return res;  
}  

int main()  
{   
    n = get(); m = get(); k = get(); int x, y;  
    for (int i = 1; i <= m; ++i)  
    {  
        x = get(); y = get();   
        add(x, y, get());  
    }  
    for (int i = 1; i <= k; ++i)   
        col(i) = get(), 
		id(i) = get();  //a
    sort(a + 1, a + k + 1, cmp);  //col
    for (int i = 1; i <= k; ++i)  {  
        if (col(i) != col(i - 1)) 
		    Cn++; 
		c[i] = Cn;  
    }  
    for (int i = 1; i <= k; ++i) col(i) = c[i]; //离散化 
    Cn = (1 << Cn);  
    memset(g, Maxn, sizeof(g));  
    for (int i = 1; i < Cn; ++i)  {  
        memset(f, Maxn, sizeof(f));  
        int cnt = 0;   
        for (int j = 1; j <= k; ++j)   
            if ((1 << col(j) - 1) & i) 
		        f[id(j)][1 << cnt++] = 0;  
        g[i] = solve(cnt);  
     }   
    for (int i = 1; i < Cn; ++i)  
        for (int j = (i - 1) & i; j; j = (j - 1) & i)  
            CkMin(g[i], g[j] + g[i - j]);  
    return put(g[Cn - 1]), 0;  
}  
posted @ 2019-05-08 11:11  y2823774827y  阅读(246)  评论(0编辑  收藏  举报