当前位置:编程学习 > C/C++ >>

hdu4085 Peach Blossom Spring 斯坦纳树,状态dp

(1)集合中元素表示(1<<i), i从0开始
 
(2)注意dp[i][ss] = min(dp[i][ss], dp[i][rr | s[i]] + dp[i][(ss ^ rr) | s[i]]);,后面的要 |s[i],保证状态的正确
 
(3)INF初始化CLR(dp, 0x3f)
 
(4)注意斯坦纳树状态理解,分层松弛的理解
 
参考:http://endlesscount.blog.163.com/blog/static/821197872012525113427573/
 
//#pragma warning (disable: 4786)  
//#pragma comment (linker, "/STACK:16777216")  
//HEAD  
#include <cstdio>  
#include <ctime>  
#include <cstdlib>  
#include <cstring>  
#include <queue>  
#include <string>  
#include <set>  
#include <stack>  
#include <map>  
#include <cmath>  
#include <vector>  
#include <iostream>  
#include <algorithm>  
using namespace std;  
//LOOP  
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)  
#define FED(i, b, a) for(int i = (b); i>= (a); --i)  
#define REP(i, N) for(int i = 0; i < (N); ++i)  
#define CLR(A,value) memset(A,value,sizeof(A))  
//INPUT  
#define RI(n) scanf("%d", &n)  
#define RII(n, m) scanf("%d%d", &n, &m)  
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)  
#define RS(s) scanf("%s", s)  
  
typedef long long LL;  
const int INF = 0x3f3f3f3f;  
const double eps = 1e-10;  
const int MAXN = 1000010;  
  
struct node{  
    int to, next, l;  
};  
int tol;  
node adj[2010];  
int head[55];  
void init_adj()  
{  
    tol = 0;  
    CLR(head, -1);  
}  
void add_edge(int x, int y, int ll)  
{  
    adj[tol].to = y;  
    adj[tol].l = ll;  
    adj[tol].next = head[x];  
    head[x] = tol++;  
}  
int dp[55][1 << 11];  
queue<int>q;  
bool inq[55][1 << 11];  
int d[1 << 11];  
int s[55];  
int n, m, k;  
int cnt, ALL;  
  
bool check(int ss)  
{  
    int num = 0;  
    for (int i = 0; i < cnt; i++)  
        if (ss & (1 << i))  
            num += i < k ? 1 : -1;  
    if (!num) return 1;  
    return 0;  
}  
  
void spfa()  
{  
    while (!q.empty())  
    {  
        int u = q.front(); q.pop();  
        int ui = u / 10000;  
        int uss = u % 10000;  
        inq[ui][uss] = 0;  
        for (int r = head[ui]; r != -1; r = adj[r].next)  
        {  
            int vi = adj[r].to;  
            int vss = uss | s[vi];  
            if (dp[vi][vss] > dp[ui][uss] + adj[r].l)  
            {  
                dp[vi][vss] = dp[ui][uss] + adj[r].l;  
                if (vss == uss && !inq[vi][vss]) /// 同层且不再队列中  
                {  
                    inq[vi][vss] = 1;  
                    q.push(vi * 10000 + vss);  
                }  
            }  
        }  
    }  
}  
  
void solve()  
{  
    while (!q.empty()) q.pop();  
    CLR(inq, 0);  
    FE(ss, 0, ALL)  
    {  
        FE(i, 1, n)  
        {  
            for (int rr = ss & (ss - 1); rr; rr = (rr - 1) & ss)///ss  
                    dp[i][ss] = min(dp[i][ss], dp[i][rr | s[i]] + dp[i][(ss ^ rr) | s[i]]);  
            if (dp[i][ss] < INF)  
                q.push(i * 10000 + ss), inq[i][ss] = 1;  
        }  
        spfa();  
    }  
  
    CLR(d, 0x3f);  
    FE(ss, 0, ALL) FE(j, 1, n)  
        d[ss] = min(d[ss], dp[j][ss]);  
  
    REP(ss, ALL + 1)  
        for(int rr = ss & (ss - 1); rr; rr = (rr - 1) & ss)  
            if (check(rr) && check(ss ^ rr))  
                d[ss] = min(d[ss], d[rr] + d[ss ^ rr]);  
  
    if (d[ALL] == INF) printf("No solution\n");  
    else printf("%d\n", d[ALL]);  
}  
  
  
void init()  
{  
    int x, y, l;  
    init_adj();  
    RIII(n, m, k);  
    while (m--)  
    {  
        RIII(x, y, l);  
        add_edge(x, y, l);  
        add_edge(y, x, l);  
    }  
  
    cnt = 2 * k;  
    ALL = (1 << cnt) - 1;  
  
    CLR(s, 0);  
    CLR(dp, 0x3f);  
  
    FE(i, 1, k)///集合  
    {  
        s[i] = 1 << (i - 1);  
        dp[i][s[i]] = 0;  
        s[n - k + i] = 1 << (k + i - 1);  
        dp[n - k + i][s[n - k + i]] = 0;  
    }  
}  
  
int main ()  
{  
    int T;  
    RI(T);  
    while (T--)  
    {  
        init();  
        solve();  
    }  
    return 0;  
}  

 

 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,